<script lang="ts" setup>
import type { Node } from '@antv/x6'
import { Graph, Shape } from '@antv/x6'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { Export } from '@antv/x6-plugin-export'
import { History } from '@antv/x6-plugin-history'
import { Keyboard } from '@antv/x6-plugin-keyboard'
// import { Scroller } from '@antv/x6-plugin-scroller'
import { Selection } from '@antv/x6-plugin-selection'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Stencil } from '@antv/x6-plugin-stencil'
import { Transform } from '@antv/x6-plugin-transform'
import '@antv/x6-vue-shape'
import {
  ArrowDown,
  ArrowRight,
  Back,
  Bottom,
  Close,
  Expand,
  Fold,
  Plus,
  Refresh,
  RefreshLeft,
  RefreshRight,
  Top,
  Upload,
} from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import LeftSidePanel from './components/LeftSidePanel.vue'
import NodePropertiesPanel from './components/NodePropertiesPanel.vue'
import NodeTooltip from './components/NodeTooltip.vue'
import RightSidePanel from './components/RightSidePanel.vue'
import * as WebsocketComponent from './components/websocket.vue'
import type { NodeConfiguration, NodePin } from './utils/nodeInfo'
import { getNodeConfiguration, getNodeConfigurationFromJSON, loadNodeRegistrationsWithCache, loadNodeRegistrationsFromJSON, registerNodesFromJSON } from './utils/nodeInfo'
import { canvasList, createCanvas, deleteCanvas } from '/@/api/antvx6'
import '/@/assets/styles/node-fonts.css'

defineOptions({
  name: 'AntvX6Demo',
})

// Graph reference for controlling the canvas from properties panel
const graphRef = ref<Graph | null>(null)
const activeTab = ref('图纸选项')
// 追踪当前选中的节点
const selectedNode = ref<Node | null>(null)
// 追踪节点是否被选中的状态
const isNodeSelected = ref(false)
// 追踪是否有多个节点被选中的状态
const isMultipleNodesSelected = ref(false)

// 追踪当前选中的边
const selectedEdge = ref<any>(null)
// 追踪边是否被选中的状态
const isEdgeSelected = ref(false)

// 气泡提示相关状态
const tooltipVisible = ref(false)
const tooltipTriggerRef = ref<HTMLElement>()
const tooltipNodeType = ref('')
const tooltipNodeId = ref('')

// 全局默认属性
const defaultProperties = {
  backgroundColor: '#FFFFFF',
  gridType: '点状',
  gridColor: '#CCCCCC',
  pageLineVisible: true,
  referenceStandardsVisible: true, // 默认开启拖动按钮
  elementsStandard: false,
  guidelineStandard: true,
  canvasWidth: 600,
  canvasHeight: 800,
  baseCanvasWidth: 600, // 基础宽度，不受缩放影响
  baseCanvasHeight: 800, // 基础高度，不受缩放影响
}

// 当前活动图纸的属性
const backgroundColor = ref(defaultProperties.backgroundColor)
const gridType = ref(defaultProperties.gridType)
const gridColor = ref(defaultProperties.gridColor)
const pageLineVisible = ref(defaultProperties.pageLineVisible)
const referenceStandardsVisible = ref(defaultProperties.referenceStandardsVisible)
const elementsStandard = ref(defaultProperties.elementsStandard)
const guidelineStandard = ref(defaultProperties.guidelineStandard)
// Canvas size controls
const canvasWidth = ref(600)
const canvasHeight = ref(800)
const baseCanvasWidth = ref(600)
const baseCanvasHeight = ref(800)

// 侧边栏折叠状态
const leftSidebarCollapsed = ref(false)
const rightSidebarCollapsed = ref(false)

// 图纸类型定义
interface Drawing {
  id: number
  name: string
  date: string
  active: boolean
  canDelete: boolean
}

// 图纸管理
const drawings = ref<Drawing[]>([])
const activeDrawingId = ref(0)

// 初始化画布列表
const initializeDrawings = async () => {
  try {
    // 从接口获取画布列表
    const response = await canvasList()
    const canvases = Array.isArray((response as any).data) ? (response as any).data : Array.isArray(response) ? response : []


    if (Array.isArray(canvases) && canvases.length > 0) {
      // 使用接口返回的画布数据，并按照图纸编号排序
      drawings.value = canvases
        .map((canvas: any) => ({
          id: canvas.id,
          name: canvas.name,
          date: canvas.date || new Date().toISOString().split('T')[0],
          active: canvas.id === activeDrawingId.value,
          // 图纸1（检查名称包含"图纸 1"或"图纸1"或编号为1的图纸）不可删除
          canDelete:
            canvas.canDelete !== false &&
            !canvas.name.includes('图纸 1') &&
            !canvas.name.includes('图纸1') &&
            !(canvas.name.match(/\d+/)?.[0] === '1'),
        }))
        .sort((a, b) => {
          // 从名称中提取数字进行排序
          const numA = parseInt(a.name.match(/\d+/)?.[0] || '0')
          const numB = parseInt(b.name.match(/\d+/)?.[0] || '0')
          return numA - numB
        })


      // 如果没有激活的画布，激活第一个
      if (!drawings.value.some((d) => d.active)) {
        drawings.value[0].active = true
        activeDrawingId.value = drawings.value[0].id
      }
    } else {
      // 如果接口没有返回数据，初始化一个默认的图纸1
      drawings.value = [
        {
          id: 1,
          name: '图纸 1',
          date: new Date().toISOString().split('T')[0],
          active: true,
          canDelete: false,
        },
      ]
      activeDrawingId.value = 1
    }
  } catch (error) {
    ElMessage.error('获取画布列表失败，请检查网络连接')

    // 接口失败时，初始化一个默认的图纸1
    drawings.value = [
      {
        id: 1,
        name: '图纸 1',
        date: new Date().toISOString().split('T')[0],
        active: true,
        canDelete: false,
      },
    ]
    activeDrawingId.value = 1
    console.log('接口失败，初始化默认图纸1:', drawings.value)
  }
}

// 在组件挂载时初始化画布列表
onMounted(() => {
  initializeDrawings()
})

// 用于存储每个图纸的画布内容
const graphContents = ref(new Map())

// 存储每个图纸的属性
const drawingProperties = ref(new Map())

// 存储选择组数据（添加新功能）
const selectionGroups = ref(new Map<number, Map<string, any>>())
const activeSelectionGroup = ref<any>(null)
const isEditingGroup = ref(false)
const groupBackgroundColor = ref('#E8F4FF')
const groupText = ref('选择组')
const isSelectionGroupsCollapsed = ref(false) // 添加折叠状态变量

// 节点位置和大小状态
const nodeX = ref(0)
const nodeY = ref(0)
const nodeWidth = ref(0)
const nodeHeight = ref(0)
const nodeBorderWidth = ref(1) // 添加边框宽度变量
const nodeFontSize = ref(12) // 添加文本大小变量
const nodeFontFamily = ref('Arial') // 添加字体变量
// 节点颜色格式属性
const nodeFillColor = ref('#EFF4FF') // 节点填充颜色
const nodeStrokeColor = ref('#5F95FF') // 节点边框颜色
const nodeLabelColor = ref('#262626') // 节点文本颜色

// 边的格式属性状态
const edgeSourcePort = ref('') // 首端连接桩
const edgeTargetPort = ref('') // 末端连接桩

// 用于触发连接桩选项更新的响应式变量
const nodesUpdateTrigger = ref(0)
const edgeRouterType = ref('无') // 路由类型：无、正交
const edgeConnectorType = ref('无') // 连接类型：无、平滑、圆角
const edgeStrokeColor = ref('#000000') // 线条颜色
const edgeStrokeWidth = ref(2) // 线条宽度
const edgeFillColor = ref('#ffffff') // 填充颜色（用于边的标签背景）
const edgeTextColor = ref('#333333') // 文本颜色
const edgeFontFamily = ref('Arial') // 字体
const edgeFontSize = ref(12) // 字体大小

// 路由类型选项
const routerTypeOptions = ref([
  { label: '无', value: '无' },
  { label: '正交', value: '正交' }
])

// 连接类型选项
const connectorTypeOptions = ref([
  { label: '无', value: '无' },
  { label: '平滑', value: '平滑' },
  { label: '圆角', value: '圆角' }
])

// 字体选项数组 - 精简版
const fontOptions = ref([
  // 中文字体
  { label: '微软雅黑', value: 'Microsoft YaHei' },
  { label: '黑体', value: 'SimHei' },
  { label: '宋体', value: 'SimSun' },
  { label: '楷体', value: 'KaiTi' },

  // 英文字体
  { label: 'Arial', value: 'Arial' },
  { label: 'Helvetica', value: 'Helvetica' },
  { label: 'Times New Roman', value: 'Times New Roman' },
  { label: 'Georgia', value: 'Georgia' },
  { label: 'Verdana', value: 'Verdana' },
])

// 存储模块数据
const modules = ref(new Map<number, Map<string, any>>())
const activeModule = ref<any>(null)

// 模块创建/打开对话框
const moduleDialogVisible = ref(false)
const moduleDialogTitle = ref('创建模块')
const moduleFormData = ref({
  resourceId: '',
  modelId: '',
  projectId: '',
  name: '',
  permission: 'private', // 默认私有
  type: '元件',
  category: '',
  description: '',
})
const isCreatingModule = ref(true)

const moduleFormRules = ref({
  projectId: [{ required: true, message: '请输入项目ID', trigger: 'blur' }],
  name: [{ required: true, message: '请输入模块名称', trigger: 'blur' }],
})

const moduleFormRef = ref()

// 当前模块ID
const currentModuleId = ref('')

// 图纸右键菜单
const drawingMenuVisible = ref(false)
const drawingMenuPosition = ref({ x: 0, y: 0 })
const selectedDrawingId = ref<number | null>(null)

// 图片上传相关状态
const imageUploadDialogVisible = ref(false)
const imageFileInputRef = ref<HTMLInputElement>()
const selectedImageFile = ref<File | null>(null)
const selectedImagePreview = ref<string>('')

// 图片尺寸更新防抖
const imageUpdateTimeouts = new Map<string, ReturnType<typeof setTimeout>>()

// 图纸右键菜单选项
const drawingMenuOptions = [{ label: '删除', value: 'delete', icon: 'delete-bin-line' }]

// Grid type options
const gridTypeOptions = [
  { value: '隐藏', label: '隐藏' },
  { value: '点状', label: '点状' },
  { value: '网状', label: '网状' },
  { value: '双层网状', label: '双层网状' },
]

// 右键菜单相关状态
const contextMenuVisible = ref(false)
const contextMenuPosition = ref({ x: 0, y: 0 })
const currentCell = ref<any>(null)

// 右键菜单选项
const menuOptions = [
  { label: '剪切', value: 'cut', shortcut: 'Ctrl + X', icon: 'scissors-cut-line' },
  { label: '复制', value: 'copy', shortcut: 'Ctrl + C', icon: 'file-copy-line' },
  { label: '创建副本', value: 'clone', shortcut: 'Ctrl + D', icon: 'file-copy-2-line' },
  { label: '删除', value: 'delete', shortcut: 'DELETE', icon: 'delete-bin-line' },
  { label: '上传图片', value: 'uploadImage', icon: 'image-add-line' },
  { label: '移除图片', value: 'removeImage', icon: 'image-close-line' },
  { label: '创建选择组', value: 'createGroup', icon: 'group-line' },
  { label: '创建模块', value: 'createModule', icon: 'folder-add-line' },
  { label: '导出为SVG图片', value: 'exportSVG', icon: 'download-cloud-line' },
  { label: '顺时针旋转', value: 'rotateClockwise', shortcut: 'Ctrl + R', icon: 'rotate-clockwise-line' },
  { label: '逆时针旋转', value: 'rotateCounterClockwise', shortcut: 'Ctrl + Shift + R', icon: 'rotate-lock-line' },
  { label: '撤销', value: 'undo', shortcut: 'Ctrl + Z', icon: 'arrow-go-back-line' },
  { label: '重做', value: 'redo', shortcut: 'Ctrl + Y', icon: 'arrow-go-forward-line' },
]

// 边的右键菜单选项
const edgeMenuOptions = [
  { label: '删除', value: 'delete', icon: 'delete-bin-line', shortcut: 'Delete' },
  { label: '编辑标签', value: 'edit-label', icon: 'edit-line' },
  { label: '复制', value: 'copy', icon: 'file-copy-line', shortcut: 'Ctrl+C' },
]

// 多选菜单选项
const multiSelectMenuOptions = [
  { label: '复制', value: 'copy', icon: 'file-copy-line', shortcut: 'Ctrl+C' },
  { label: '删除', value: 'delete', icon: 'delete-bin-line', shortcut: 'Delete' },
  { label: '创建选择组', value: 'create-group', icon: 'group-line' },
  { label: '创建模块', value: 'createModule', icon: 'folder-add-line' },
]

// 画布空白区域右键菜单选项
const canvasMenuOptions = [
  { label: '粘贴', value: 'paste', icon: 'clipboard-line', shortcut: 'Ctrl+V' },
  { label: '适应画布', value: 'fit-view', icon: 'fullscreen-line', shortcut: 'Ctrl+0' },
  { label: '放大', value: 'zoom-in', icon: 'zoom-in-line', shortcut: '滚轮向上' },
  { label: '缩小', value: 'zoom-out', icon: 'zoom-out-line', shortcut: '滚轮向下' },
  { label: '实际大小', value: 'actual-size', icon: 'aspect-ratio-line', shortcut: 'Ctrl+1' },
  { label: '全选', value: 'select-all', icon: 'checkbox-multiple-line', shortcut: 'Ctrl+A' },
  { label: '撤销', value: 'undo', icon: 'arrow-go-back-line', shortcut: 'Ctrl+Z' },
  { label: '重做', value: 'redo', icon: 'arrow-go-forward-line', shortcut: 'Ctrl+Y' },
  { label: '导出为SVG图片', value: 'export-svg', icon: 'file-download-line', shortcut: 'Ctrl+E' },
  { label: '导出JSON格式数据', value: 'export-json', icon: 'file-code-line' },
]

// 模块节点菜单选项
const moduleMenuOptions = [
  { label: '打开模块', value: 'openModule', icon: 'folders-fill' },
  { label: '上传图片', value: 'uploadImage', icon: 'image-add-line' },
  { label: '移除图片', value: 'removeImage', icon: 'image-edit-line' },
  { label: '剪切', value: 'cut', shortcut: 'Ctrl + X', icon: 'scissors-cut-line' },
  { label: '复制', value: 'copy', shortcut: 'Ctrl + C', icon: 'file-copy-line' },
  { label: '创建副本', value: 'clone', shortcut: 'Ctrl + D', icon: 'file-copy-2-line' },
  { label: '删除', value: 'delete', shortcut: 'DELETE', icon: 'delete-bin-line' },
  { label: '导出为SVG图片', value: 'exportSVG', icon: 'download-cloud-line' },
  { label: '顺时针旋转', value: 'rotateClockwise', shortcut: 'Ctrl + R', icon: 'rotate-clockwise-line' },
  { label: '逆时针旋转', value: 'rotateCounterClockwise', shortcut: 'Ctrl + Shift + R', icon: 'rotate-lock-line' },
  { label: '撤销', value: 'undo', shortcut: 'Ctrl + Z', icon: 'arrow-go-back-line' },
  { label: '重做', value: 'redo', shortcut: 'Ctrl + Y', icon: 'arrow-go-forward-line' },
]

// 当前显示的菜单选项
const currentMenuOptions = ref(menuOptions)

// 节点属性配置相关状态
const currentNodeConfiguration = ref<NodeConfiguration | null>(null)
const nodePropertiesData = ref<Record<string, any>>({})

// JSON节点配置相关状态
const nodeRegistrationsFromJSON = ref<any[]>([])
const stencilGroupsFromJSON = ref<any[]>([])
const isNodesLoaded = ref(false)

// 控制节点标签显示/隐藏的方法
const toggleNodeLabels = (show: boolean) => {
  if (!graphRef.value) return

  const nodes = graphRef.value.getNodes()
  nodes.forEach((node: any) => {
    if (show) {
      // 显示标签：获取节点标签文本并设置到节点上
      const nodeLabel = node.label || node.getData()?.label || node.prop('data/label') || getNodeDefaultLabel(node)
      if (nodeLabel) {
        // 动态添加文本元素
        node.attr({
          label: {
            text: nodeLabel,
            refX: '50%',
            refY: '100%',
            refY2: 8,
            textAnchor: 'middle',
            textVerticalAnchor: 'top',
            fontSize: 12,
            fill: '#333',
            fontFamily: 'Arial',
            visibility: 'visible',
          },
        })

        // 确保节点有text元素
        const markup = node.markup || []
        const hasTextElement = markup.some((item: any) => item.tagName === 'text' && item.selector === 'label')
        if (!hasTextElement) {
          markup.push({
            tagName: 'text',
            selector: 'label',
          })
          node.setMarkup(markup)
        }
      }
    } else {
      // 隐藏标签
      node.attr('label/visibility', 'hidden')
    }
  })
}

// 获取节点的默认标签
const getNodeDefaultLabel = (node: any) => {
  const shape = node.shape
  // 从节点配置中获取默认标签
  const nodeConfig = nodeRegistrationsFromJSON.value.find((reg) => reg.nodeType === shape)
  if (nodeConfig && nodeConfig.stencilConfig && nodeConfig.stencilConfig.length > 0) {
    return nodeConfig.stencilConfig[0].label || nodeConfig.name
  }
  return nodeConfig?.name || shape
}

// 为单个节点应用标签设置
const applyLabelSettingToNode = (node: any) => {
  if (elementsStandard.value) {
    // 显示标签
    const nodeLabel = node.label || node.getData()?.label || node.prop('data/label') || getNodeDefaultLabel(node)
    if (nodeLabel) {
      node.attr({
        label: {
          text: nodeLabel,
          refX: '50%',
          refY: '100%',
          refY2: 8,
          textAnchor: 'middle',
          textVerticalAnchor: 'top',
          fontSize: 12,
          fill: '#333',
          fontFamily: 'Arial',
          visibility: 'visible',
        },
      })

      // 确保节点有text元素
      const markup = node.markup || []
      const hasTextElement = markup.some((item: any) => item.tagName === 'text' && item.selector === 'label')
      if (!hasTextElement) {
        markup.push({
          tagName: 'text',
          selector: 'label',
        })
        node.setMarkup(markup)
      }
    }
  } else {
    // 隐藏标签
    node.attr('label/visibility', 'hidden')
  }
}

// 监听元件标签设置变化
watch(elementsStandard, (newValue) => {
  toggleNodeLabels(newValue)
})

// 设置 Stencil 节点气泡提示
const setupStencilTooltip = (stencil: any) => {
  // console.log('[Tooltip] Setting up stencil tooltip...')

  const setupTooltipForContainer = (container: HTMLElement) => {
    // console.log('[Tooltip] Setting up tooltip for container:', container)

    // 使用事件委托，监听容器的鼠标事件
    container.addEventListener(
      'mouseenter',
      (event) => {
        const target = event.target as HTMLElement

        // 查找最近的节点元素
        const nodeElement = target.closest('.x6-node') || target.closest('[data-shape]') || target.closest('g[data-cell-id]')

        if (nodeElement) {
          // console.log('[Tooltip] Found node element on mouseenter:', nodeElement)

          // 尝试多种方式获取节点类型
          let nodeType = ''

          // 方法1: 从 data-shape 属性
          nodeType = (nodeElement as HTMLElement).dataset.shape || ''

          // 方法2: 从子元素的 data-shape
          if (!nodeType) {
            const shapeElement = nodeElement.querySelector('[data-shape]')
            nodeType = shapeElement?.getAttribute('data-shape') || ''
          }

          // 方法3: 从 data-cell-id 通过图形实例获取
          if (!nodeType) {
            const cellId = (nodeElement as HTMLElement).dataset.cellId
            if (cellId && graphRef.value) {
              try {
                const cell = graphRef.value.getCellById(cellId)
                nodeType = cell?.shape || ''
              } catch {
                // console.warn('[Tooltip] Failed to get cell shape:', error)
              }
            }
          }

          // console.log('[Tooltip] Found node type:', nodeType)

          if (nodeType) {
            tooltipNodeType.value = nodeType
            tooltipNodeId.value = (nodeElement as HTMLElement).dataset.cellId || ''
            tooltipTriggerRef.value = nodeElement as HTMLElement
            tooltipVisible.value = true
          }
        }
      },
      true
    ) // 使用捕获模式

    container.addEventListener(
      'mouseleave',
      (event) => {
        const relatedTarget = event.relatedTarget as HTMLElement

        // 检查是否真的离开了容器
        if (!container.contains(relatedTarget)) {
          // console.log('[Tooltip] Mouse left container, hiding tooltip')
          tooltipVisible.value = false
          tooltipNodeType.value = ''
          tooltipNodeId.value = ''
        }
      },
      true
    )
  }

  // 等待 stencil 容器准备好
  const waitForStencil = () => {
    const stencilContainer = stencil.container
    if (!stencilContainer) {
      // console.warn('[Tooltip] Stencil container not found, retrying...')
      setTimeout(waitForStencil, 200)
      return
    }

    // console.log('[Tooltip] Stencil container found:', stencilContainer)

    // 立即设置已存在的节点
    setupTooltipForContainer(stencilContainer)

    // 使用 MutationObserver 监听新添加的节点
    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === 'childList') {
          mutation.addedNodes.forEach((node) => {
            if (node.nodeType === 1) {
              // Node.ELEMENT_NODE = 1
              const element = node as HTMLElement

              // 检查新添加的元素是否包含节点
              const nodeElements = element.querySelectorAll('.x6-node, [data-shape], g[data-cell-id]')
              if (nodeElements.length > 0) {
                // 重新设置事件监听
                setupTooltipForContainer(stencilContainer)
              }
            }
          })
        }
      })
    })

    // 开始观察 stencil 容器的变化
    observer.observe(stencilContainer, {
      childList: true,
      subtree: true,
    })
  }

  // 延迟执行，确保 DOM 已渲染
  setTimeout(waitForStencil, 800)
}

// 完全基于JSON数据动态创建Stencil组和节点 - 从nodeRegistrations中获取stencilConfig
const loadStencilFromJSON = (graph: any, stencil: any, stencilGroups: any[], nodeRegistrations: any[]) => {
  try {
    // 按stencilGroup分组节点的stencilConfig
    const nodesByGroup = new Map<string, any[]>()
    nodeRegistrations.forEach((nodeReg: any) => {
      if (nodeReg.stencilConfig && nodeReg.stencilConfig.length > 0) {
        const groupName = nodeReg.stencilGroup
        if (!nodesByGroup.has(groupName)) {
          nodesByGroup.set(groupName, [])
        }

        // 为每个stencilConfig实例添加nodeType信息
        nodeReg.stencilConfig.forEach((stencilInstance: any) => {
          nodesByGroup.get(groupName)!.push({
            ...stencilInstance,
            nodeType: nodeReg.nodeType,
          })
        })
      }
    })

    // 为每个组创建并加载节点
    stencilGroups.forEach((groupConfig: any) => {
      const groupNodes = nodesByGroup.get(groupConfig.name) || []

      if (groupNodes.length > 0) {
        const stencilNodesArray: any[] = []

        // 遍历该组的所有节点配置
        groupNodes.forEach((stencilNode: any) => {
          const nodeConfig: any = {
            shape: stencilNode.nodeType,
            label: stencilNode.label || '',
            data: { label: stencilNode.label || '' },
            ...(stencilNode.attrs && { attrs: stencilNode.attrs }),
          }

          // 确保节点文本正确显示
          if (stencilNode.label) {
            if (!nodeConfig.attrs) {
              nodeConfig.attrs = {}
            }
            // 设置text属性（主要显示属性，不受elementsStandard影响）
            nodeConfig.attrs.text = {
              ...nodeConfig.attrs.text,
              text: stencilNode.label,
              fill: '#262626',
              fontSize: 12,
              fontFamily: 'Arial',
              textAnchor: 'middle',
              textVerticalAnchor: 'middle',
            }
          }

          const createdNode = graph.createNode(nodeConfig)
          stencilNodesArray.push(createdNode)
        })

        stencil.load(stencilNodesArray, groupConfig.name)
        // console.log(`已加载 ${stencilNodesArray.length} 个节点到组 ${groupConfig.title} (${groupConfig.name})`)
      }
    })

    // 添加节点气泡提示事件监听
    setupStencilTooltip(stencil)
  } catch (error) {
    console.error('加载Stencil节点失败:', error)
  }
}

// 键盘状态
const ctrlKeyPressed = ref(false)
const spaceKeyPressed = ref(false) // 空格键状态

// 侧边栏切换方法
const toggleLeftSidebar = () => {
  leftSidebarCollapsed.value = !leftSidebarCollapsed.value
}

const toggleRightSidebar = () => {
  rightSidebarCollapsed.value = !rightSidebarCollapsed.value
}

// 获取下一个可用图纸ID的函数
const getNextDrawingId = () => {
  // 从ID 2开始，因为ID 0是图纸1，新图纸从2开始
  let nextId = 2

  // 获取当前所有图纸ID
  const ids = new Set(drawings.value.map((drawing) => drawing.id))

  // 找出最小未使用ID
  while (ids.has(nextId)) {
    nextId++
  }

  return nextId
}

// 保存当前图纸状态
const saveDrawingState = () => {
  if (!graphRef.value) return

  // 保存画布内容
  const currentGraphData = graphRef.value.toJSON()
  graphContents.value.set(activeDrawingId.value, currentGraphData)

  // 保存当前图纸属性
  saveCurrentDrawingProperties()

  // 重置选中状态和tab
  selectedNode.value = null
  isNodeSelected.value = false
  isMultipleNodesSelected.value = false
  activeTab.value = '图纸选项'
}

// 创建新图纸
const createNewDrawing = async () => {
  // 保存当前图纸状态
  if (graphRef.value) {
    saveDrawingState()
  }

  try {
    // 基于本地画布数量生成新的ID（不调用列表接口）
    const maxDrawingNumber = drawings.value.reduce((max, drawing) => {
      const num = parseInt(drawing.name.match(/\d+/)?.[0] || '0')
      return Math.max(max, num)
    }, 0)

    // 新图纸编号为最大编号+1
    let newId = maxDrawingNumber + 1

    // 确保新ID不与现有ID冲突
    const existingIds = new Set(drawings.value.map((drawing) => drawing.id))
    while (existingIds.has(newId)) {
      newId++
    }

    console.log('生成新图纸ID:', newId)

    // 创建新图纸对象
    const newDrawing = {
      id: newId,
      name: `图纸 ${newId}`,
      date: new Date().toISOString().split('T')[0],
      active: true,
      // 图纸1不可删除，其他图纸可以删除
      canDelete: newId !== 1,
    }

    // 调用接口保存新建的图纸
    await createCanvas({
      id: newId,
      name: `图纸 ${newId}`,
      date: new Date().toISOString().split('T')[0],
    })

    console.log('新图纸创建成功，更新本地列表')

    // 只有API成功后才更新本地图纸列表
    drawings.value.forEach((drawing) => {
      drawing.active = false
    })
    drawings.value.push(newDrawing)

    // 按图纸编号排序
    drawings.value.sort((a, b) => {
      const numA = parseInt(a.name.match(/\d+/)?.[0] || '0')
      const numB = parseInt(b.name.match(/\d+/)?.[0] || '0')
      return numA - numB
    })

    // 更新当前图纸ID
    activeDrawingId.value = newDrawing.id

    // 清空画布
    if (graphRef.value) {
      graphRef.value.clearCells()
    }

    // 应用默认属性
    applyDrawingProperties(defaultProperties)

    ElMessage.success(`图纸 ${newId} 创建成功`)
  } catch (error) {
    console.error(`创建图纸失败:`, error)
    ElMessage.error(`创建图纸失败，请重试`)
  }
}

// 切换到指定图纸
const switchToDrawing = (id: number) => {
  // 保存当前图纸状态
  if (graphRef.value) {
    const currentGraphData = graphRef.value.toJSON()
    graphContents.value.set(activeDrawingId.value, currentGraphData)

    // 保存当前图纸属性
    saveCurrentDrawingProperties()
  }

  drawings.value.forEach((drawing) => {
    drawing.active = drawing.id === id
  })
  activeDrawingId.value = id

  // 重置选中状态和tab
  selectedNode.value = null
  isNodeSelected.value = false
  isMultipleNodesSelected.value = false
  activeTab.value = '图纸选项'

  // 加载目标图纸内容
  if (graphRef.value) {
    graphRef.value.clearCells()
    const targetGraphData = graphContents.value.get(id)
    if (targetGraphData) {
      graphRef.value.fromJSON(targetGraphData)

      // 确保切换图纸后的边不显示箭头（未选中状态）
      removeAllEdgeArrows()
    }

    // 加载目标图纸属性
    loadDrawingProperties(id)

    // 加载选择组
    loadSelectionGroups(id)
  }
}

// 保存当前图纸的属性
const saveCurrentDrawingProperties = () => {
  // 获取当前图纸的已有属性，确保我们不丢失基础尺寸
  const existingProps = drawingProperties.value.get(activeDrawingId.value) || {}
  const currentProperties = {
    backgroundColor: backgroundColor.value,
    gridType: gridType.value,
    gridColor: gridColor.value,
    pageLineVisible: pageLineVisible.value,
    referenceStandardsVisible: referenceStandardsVisible.value,
    elementsStandard: elementsStandard.value,
    guidelineStandard: guidelineStandard.value,
    canvasWidth: canvasWidth.value,
    canvasHeight: canvasHeight.value,
    // 保留原有的基础尺寸，如果不存在则使用当前尺寸
    baseCanvasWidth: existingProps.baseCanvasWidth || canvasWidth.value,
    baseCanvasHeight: existingProps.baseCanvasHeight || canvasHeight.value,
  }

  drawingProperties.value.set(activeDrawingId.value, currentProperties)
}

// 移除所有边的箭头标记（确保未选中状态下不显示箭头）
const removeAllEdgeArrows = () => {
  if (!graphRef.value) return

  const edges = graphRef.value.getEdges()
  edges.forEach((edge) => {
    edge.attr('line/targetMarker', null)
  })
}

// 加载指定图纸的属性
const loadDrawingProperties = (drawingId: number) => {
  // 获取图纸属性
  const drawingProps = drawingProperties.value.get(drawingId)
  if (!drawingProps) return

  // 设置常用属性
  backgroundColor.value = drawingProps.backgroundColor || '#F8F9FA'
  gridType.value = drawingProps.gridType || '网状'
  gridColor.value = drawingProps.gridColor || '#EAECEE'
  pageLineVisible.value = drawingProps.pageLineVisible === undefined ? true : drawingProps.pageLineVisible
  referenceStandardsVisible.value = drawingProps.referenceStandardsVisible === undefined ? true : drawingProps.referenceStandardsVisible
  elementsStandard.value = drawingProps.elementsStandard === undefined ? false : drawingProps.elementsStandard
  guidelineStandard.value = drawingProps.guidelineStandard === undefined ? true : drawingProps.guidelineStandard
  canvasWidth.value = drawingProps.canvasWidth || 600
  canvasHeight.value = drawingProps.canvasHeight || 800
  currentZoom.value = drawingProps.currentZoom || 100
  baseCanvasWidth.value = drawingProps.baseCanvasWidth || 600
  baseCanvasHeight.value = drawingProps.baseCanvasHeight || 800

  // 应用画布背景
  updateBackgroundColor(backgroundColor.value)
  // 应用网格
  updateGridType(gridType.value)
  // 应用元件标签设置
  toggleNodeLabels(elementsStandard.value)
  // 应用缩放
  if (graphRef.value && currentZoom.value !== 100) {
    graphRef.value.zoom(currentZoom.value / 100)
  }

  // 加载选择组
  loadSelectionGroups(drawingId)

  // 加载模块
  loadModules(drawingId)
}

// 应用属性到界面和图表
const applyDrawingProperties = (props: any) => {
  // 更新界面显示的属性值
  backgroundColor.value = props.backgroundColor
  gridType.value = props.gridType
  gridColor.value = props.gridColor
  pageLineVisible.value = props.pageLineVisible
  referenceStandardsVisible.value = props.referenceStandardsVisible
  elementsStandard.value = props.elementsStandard
  guidelineStandard.value = props.guidelineStandard
  canvasWidth.value = props.canvasWidth
  canvasHeight.value = props.canvasHeight

  // 应用属性到图表
  if (graphRef.value) {
    // 应用背景色
    graphRef.value.drawBackground({
      color: props.backgroundColor,
    })

    // 应用网格设置
    updateGridType(props.gridType)

    // 应用元件标签设置
    toggleNodeLabels(props.elementsStandard)

    // // 应用画布大小
    // graphRef.value.resize(props.canvasWidth, props.canvasHeight)
    // const container = document.getElementById('graph-container')
    // if (container) {
    //   container.style.width = `${props.canvasWidth}px`
    //   container.style.height = `${props.canvasHeight}px`
    // }

    // // 应用拖拽设置
    // if (props.referenceStandardsVisible) {
    //   graphRef.value.enablePanning()
    //   const container = document.getElementById('graph-container')
    //   if (container) {
    //     container.style.cursor = 'grab'
    //   }

    //   // 确保Scroller插件的panning也启用
    //   const scroller = graphRef.value.getPlugin('scroller') as any
    //   if (scroller && typeof scroller.enablePanning === 'function') {
    //     scroller.enablePanning()
    //   }
    // } else {
    //   graphRef.value.disablePanning()
    //   const container = document.getElementById('graph-container')
    //   if (container) {
    //     container.style.cursor = 'default'
    //   }

    //   // 确保Scroller插件的panning也禁用
    //   const scroller = graphRef.value.getPlugin('scroller') as any
    //   if (scroller && typeof scroller.disablePanning === 'function') {
    //     scroller.disablePanning()
    //   }
    // }
  }
}

// 关闭图纸
const closeDrawing = async (id: number) => {
  // 找到要关闭的图纸索引
  const index = drawings.value.findIndex((d) => d.id === id)
  if (index === -1) return

  // 检查是否可以删除
  if (!drawings.value[index].canDelete) {
    ElMessage.warning('图纸 1 不能被删除')
    return
  }

  try {
    // 调用删除画布API
    await deleteCanvas({ id })

    // 如果关闭的是当前活动图纸，需要激活其他图纸
    if (drawings.value[index].active) {
      // 重置选中状态和tab
      selectedNode.value = null
      isNodeSelected.value = false
      isMultipleNodesSelected.value = false
      activeTab.value = '图纸选项'

      // 如果有前一个图纸，激活它
      if (index > 0) {
        const prevId = drawings.value[index - 1].id
        drawings.value[index - 1].active = true
        activeDrawingId.value = prevId
        // 加载前一个图纸的内容
        if (graphRef.value) {
          graphRef.value.clearCells()
          const targetGraphData = graphContents.value.get(prevId)
          if (targetGraphData) {
            graphRef.value.fromJSON(targetGraphData)

            // 确保边不显示箭头（未选中状态）
            removeAllEdgeArrows()
          }
          // 加载前一个图纸的属性
          loadDrawingProperties(prevId)
        }
      }
      // 否则如果有后一个图纸，激活它
      else if (index < drawings.value.length - 1) {
        const nextId = drawings.value[index + 1].id
        drawings.value[index + 1].active = true
        activeDrawingId.value = nextId
        // 加载后一个图纸的内容
        if (graphRef.value) {
          graphRef.value.clearCells()
          const targetGraphData = graphContents.value.get(nextId)
          if (targetGraphData) {
            graphRef.value.fromJSON(targetGraphData)

            // 确保边不显示箭头（未选中状态）
            removeAllEdgeArrows()
          }
          // 加载后一个图纸的属性
          loadDrawingProperties(nextId)
        }
      }
    }

    // 从列表中移除图纸
    drawings.value.splice(index, 1)
    // 清除该图纸的内容
    graphContents.value.delete(id)
    // 清除该图纸的属性
    drawingProperties.value.delete(id)

    ElMessage.success('画布删除成功')
  } catch (error) {
    console.error('删除画布失败:', error)
    ElMessage.error('删除画布失败，请重试')
  }
}

// 显示图纸右键菜单
const showDrawingContextMenu = (event: MouseEvent, drawingId: number) => {
  event.preventDefault()
  selectedDrawingId.value = drawingId
  drawingMenuPosition.value = { x: event.clientX, y: event.clientY }
  drawingMenuVisible.value = true
}

// 处理图纸右键菜单操作
const handleDrawingMenuAction = async (action: string) => {
  if (action === 'delete' && selectedDrawingId.value !== null) {
    // 找到选中的图纸
    const drawingIndex = drawings.value.findIndex((d) => d.id === selectedDrawingId.value)
    if (drawingIndex !== -1) {
      const drawing = drawings.value[drawingIndex]

      // 只有可删除的图纸才能删除
      if (!drawing.canDelete) {
        ElMessage.warning('图纸 1 不能被删除')
        drawingMenuVisible.value = false
        return
      }

      try {
        // 调用删除画布API
        await deleteCanvas({ id: selectedDrawingId.value })

        const drawingId = selectedDrawingId.value
        const isActive = drawing.active

        // 如果删除的是活动图纸，需要先切换到其他图纸
        if (isActive) {
          // 尝试切换到前一个图纸
          if (drawingIndex > 0) {
            const prevId = drawings.value[drawingIndex - 1].id
            switchToDrawing(prevId)
          }
          // 否则尝试切换到后一个图纸
          else if (drawingIndex < drawings.value.length - 1) {
            const nextId = drawings.value[drawingIndex + 1].id
            switchToDrawing(nextId)
          }
        }

        // 从列表中删除
        drawings.value.splice(drawingIndex, 1)

        // 清除该图纸的内容和属性
        graphContents.value.delete(drawingId)
        drawingProperties.value.delete(drawingId)

        ElMessage.success('画布删除成功')
      } catch (error) {
        console.error('删除画布失败:', error)
        ElMessage.error('删除画布失败，请重试')
      }
    }
  }

  // 关闭菜单
  drawingMenuVisible.value = false
}

// 创建选择组
const createSelectionGroup = () => {
  if (!graphRef.value) return

  const selectedCells = graphRef.value.getSelectedCells()
  if (selectedCells.length < 2) {
    // 添加消息提示
    ElMessage.warning('创建选择组至少需要选择两个元素')
    return
  }

  // 创建唯一ID
  const groupId = `group-${Date.now()}`

  // 计算包围盒
  const bbox = graphRef.value.getCellsBBox(selectedCells)
  if (!bbox) return

  // 添加更大的内边距，使背景更宽阔
  const padding = 25

  // 创建组节点（带有背景和文本）
  const group = graphRef.value.addNode({
    id: groupId,
    shape: 'selection-group', // 使用我们注册的选择组节点类型
    x: bbox.x - padding,
    y: bbox.y - padding * 1.5, // 顶部留更多空间用于显示文本
    width: bbox.width + padding * 2,
    height: bbox.height + padding * 2.5, // 增加高度，确保文本有足够空间
    attrs: {
      body: {
        fill: groupBackgroundColor.value,
      },
      label: {
        text: groupText.value || '选择组',
      },
    },
  })

  // 存储组信息
  const groupData = {
    id: groupId,
    node: group,
    members: selectedCells.map((cell) => cell.id),
    backgroundColor: groupBackgroundColor.value,
    text: groupText.value || '选择组',
  }

  // 存储到当前图纸的选择组中
  if (!selectionGroups.value.has(activeDrawingId.value)) {
    selectionGroups.value.set(activeDrawingId.value, new Map())
  }
  const currentDrawingGroups = selectionGroups.value.get(activeDrawingId.value)
  if (currentDrawingGroups) {
    currentDrawingGroups.set(groupId, groupData)
  }

  // 设为活动组
  activeSelectionGroup.value = groupData
  isEditingGroup.value = true

  // 清除选择状态，避免显示虚线框和连接桩
  cleanupSelectionAndPorts()

  // 额外的清理，确保所有选择框都被移除
  setTimeout(() => {
    cleanupSelectionAndPorts()
    // 强制重绘以确保UI更新
    if (graphRef.value) {
      graphRef.value.cleanSelection()
      graphRef.value.trigger('blank:click')
    }
  }, 200)

  // 自动切换到选择组标签页
  activeTab.value = '选择组'

  // 保存图纸内容
  saveGraphContent()
}

// 更新选择组属性
const updateSelectionGroup = () => {
  if (!activeSelectionGroup.value || !graphRef.value) return

  const group = graphRef.value.getCellById(activeSelectionGroup.value.id)
  if (!group) return

  // 更新节点样式
  group.attr({
    body: {
      fill: groupBackgroundColor.value,
      opacity: 0.25, // 保持一致的不透明度
    },
    label: {
      text: groupText.value || '选择组',
      fontWeight: 'bold', // 保持粗体一致
      fontSize: 14, // 保持字体大小一致
    },
  })

  // 更新存储的数据
  activeSelectionGroup.value.backgroundColor = groupBackgroundColor.value
  activeSelectionGroup.value.text = groupText.value

  // 获取当前图纸的选择组
  const drawingGroups = selectionGroups.value.get(activeDrawingId.value)
  if (drawingGroups) {
    drawingGroups.set(activeSelectionGroup.value.id, activeSelectionGroup.value)
  }

  // 保存图纸内容
  const currentGraphData = graphRef.value.toJSON()
  graphContents.value.set(activeDrawingId.value, currentGraphData)
}

// 删除选择组
const deleteSelectionGroup = () => {
  if (!activeSelectionGroup.value || !graphRef.value) return

  // 删除节点
  const group = graphRef.value.getCellById(activeSelectionGroup.value.id)
  if (group) {
    graphRef.value.removeCell(group)
  }

  // 从存储中删除
  const drawingGroups = selectionGroups.value.get(activeDrawingId.value)
  if (drawingGroups) {
    drawingGroups.delete(activeSelectionGroup.value.id)
  }

  // 重置当前选择组
  activeSelectionGroup.value = null
  isEditingGroup.value = false

  // 保存图纸内容
  const currentGraphData = graphRef.value.toJSON()
  graphContents.value.set(activeDrawingId.value, currentGraphData)
}

// 保存图纸内容（包括选择组）
const saveGraphContent = () => {
  if (!graphRef.value) return

  // 保存画布内容
  const currentGraphData = graphRef.value.toJSON()
  graphContents.value.set(activeDrawingId.value, currentGraphData)

  // 保存当前图纸的属性（包括选择组和模块数据的引用）
  saveCurrentDrawingProperties()
}

// 加载选择组
const loadSelectionGroups = (drawingId: number) => {
  if (!graphRef.value) return

  // 重置选择组状态
  activeSelectionGroup.value = null
  isEditingGroup.value = false

  // 获取图纸的选择组
  const drawingGroups = selectionGroups.value.get(drawingId)
  if (!drawingGroups || drawingGroups.size === 0) return

  // 选择组已经通过图形保存在画布中，只需要更新引用
}

// 加载模块
const loadModules = (drawingId: number) => {
  if (!graphRef.value) return

  // 重置模块状态
  activeModule.value = null

  // 当图纸加载时，模块节点已经通过图形保存在画布中
  // 根据drawingProps.modules中的ID找到对应的节点，重建模块数据
  const drawingProps = drawingProperties.value.get(drawingId)
  if (!drawingProps || !drawingProps.modules || drawingProps.modules.length === 0) return

  // 获取当前所有节点
  // const cells = graphRef.value.getCells()

  // 如果没有模块Map，则创建
  if (!modules.value.has(drawingId)) {
    modules.value.set(drawingId, new Map())
  }

  const modulesMap = modules.value.get(drawingId)!

  // 遍历所有模块ID
  for (const moduleId of drawingProps.modules) {
    // 获取节点
    const node = graphRef.value.getCellById(moduleId)
    if (
      node &&
      node.isNode() && // 如果节点存在且模块数据不存在，创建模块数据
      !modulesMap.has(moduleId)
    ) {
      // 创建基本模块数据（在实际应用中应从服务器获取完整信息）
      const moduleData = {
        id: moduleId,
        node,
        name: node.attr('label/text') || '模块',
        resourceId: `a${Math.floor(Math.random() * 100000000)}`,
        modelId: `a5${Math.floor(Math.random() * 10000000)}`,
        projectId: 'my-project',
        permission: 'private',
        type: '元件',
        category: '',
        description: '',
        cells: [], // 暂时为空，打开时再填充
      }

      // 存储模块数据
      modulesMap.set(moduleId, moduleData)
    }
  }
}

// Handle active tab change
const handleActiveTabChange = (tabName: string) => {
  activeTab.value = tabName
}

// Handle elements standard change
const handleElementsStandardChange = (value: boolean) => {
  elementsStandard.value = value
  // 可以在这里添加额外的处理逻辑
}

// Handle guideline standard change
const handleGuidelineStandardChange = (value: boolean) => {
  guidelineStandard.value = value
  // 可以在这里添加额外的处理逻辑
}

// Update canvas background color
const updateBackgroundColor = (color: string | null) => {
  if (graphRef.value && color) {
    // Apply background color to canvas
    graphRef.value.drawBackground({
      color,
    })

    // Save to current drawing properties
    saveCurrentDrawingProperties()
  }
}

// Update grid color
const updateGridColor = (color: string | null) => {
  if (graphRef.value && color) {
    // 创建新的网格配置
    const gridConfig = {
      size: 10,
      visible: true,
      type: gridType.value === '点状' ? 'dot' : gridType.value === '网状' ? 'mesh' : 'doubleMesh',
      args:
        gridType.value === '点状'
          ? {
              color,
              thickness: 1,
            }
          : [
              {
                color,
                thickness: 1,
              },
              {
                color,
                thickness: 1,
                factor: 10,
              },
            ],
    }

    // 重置网格
    graphRef.value.clearGrid()
    // 应用新配置
    graphRef.value.drawGrid(gridConfig)

    // Save to current drawing properties
    saveCurrentDrawingProperties()
  }
}

// Update grid type
const updateGridType = (type: string) => {
  if (graphRef.value) {
    // 处理隐藏网格的情况
    if (type === '隐藏') {
      // 清除网格
      graphRef.value.clearGrid()
      return
    }

    // Determine the actual grid type for X6
    const x6GridType = type === '点状' ? 'dot' : type === '网状' ? 'mesh' : 'doubleMesh'

    // Apply grid type to canvas
    const gridConfig = {
      size: 10,
      visible: true,
      type: x6GridType,
      args:
        x6GridType === 'dot'
          ? {
              color: gridColor.value || '#CCCCCC',
              thickness: 1,
            }
          : [
              {
                color: gridColor.value || '#CCCCCC',
                thickness: 1,
              },
              {
                color: gridColor.value || '#CCCCCC',
                thickness: 3,
                factor: 10,
              },
            ],
    }

    // 重置网格
    graphRef.value.clearGrid()
    // 应用新配置
    graphRef.value.drawGrid(gridConfig)

    // Save to current drawing properties
    saveCurrentDrawingProperties()
  }
}

// 修改toggleReferenceStandards函数
const toggleReferenceStandards = (val: string | number | boolean) => {
  if (graphRef.value) {
    if (val) {
      // 拖动按钮开启，启用画布平移
      graphRef.value.enablePanning()
      graphRef.value.options.panning.modifiers = ['ctrl']
    } else {
      // 拖动按钮关闭，禁用画布平移
      graphRef.value.disablePanning()
    }

    // 保存用户的偏好设置
    saveCurrentDrawingProperties()
  }
}

// Toggle page dividing lines - 已注释，未使用的函数
// const togglePageLines = (visible: string | number | boolean) => {
//   if (graphRef.value) {
//     // Implementation for page dividing lines
//     console.log('Page lines visible:', visible)

//     // Save to current drawing properties
//     saveCurrentDrawingProperties()
//   }
// }

// 处理右键菜单操作
const handleContextMenuAction = (action: string) => {
  if (!graphRef.value) return

  // 获取选中的所有单元格
  const selectedCells = graphRef.value.getSelectedCells()

  switch (action) {
    case 'cut': {
      // 优先处理多选情况
      if (selectedCells.length > 0) {
        graphRef.value.cut(selectedCells)
      } else if (currentCell.value && typeof currentCell.value.id === 'string') {
        const cell = graphRef.value.getCellById(currentCell.value.id)
        if (cell) {
          graphRef.value.cut([cell])
        }
      }
      break
    }
    case 'copy': {
      // 优先处理多选情况
      if (selectedCells.length > 0) {
        graphRef.value.copy(selectedCells)
      } else if (currentCell.value && typeof currentCell.value.id === 'string') {
        const cell = graphRef.value.getCellById(currentCell.value.id)
        if (cell) {
          graphRef.value.copy([cell])
        }
      }
      break
    }
    case 'clone': {
      if (currentCell.value && typeof currentCell.value.id === 'string') {
        try {
          const cell = graphRef.value.getCellById(currentCell.value.id)
          if (cell) {
            const json = cell.toJSON()
            // Set id to undefined instead of null to avoid type error
            json.id = undefined
            json.x += 10
            json.y += 10
            graphRef.value.addNode(json)
          }
        } catch (error) {
          console.error('克隆节点失败:', error)
        }
      }
      break
    }
    case 'delete': {
      // 优先处理多选情况
      if (selectedCells.length > 0) {
        graphRef.value.removeCells(selectedCells)
      } else if (currentCell.value && typeof currentCell.value.id === 'string') {
        graphRef.value.removeCell(currentCell.value.id)
      }
      break
    }
    case 'uploadImage': {
      // 上传图片到节点
      openImageUploadDialog()
      break
    }
    case 'removeImage': {
      // 移除节点上的图片
      removeImageFromNode()
      break
    }
    case 'exportSVG': {
      // 导出为SVG图片
      exportSelectedNodesAsSVG()
      break
    }
    case 'createGroup': {
      createSelectionGroup()
      break
    }
    case 'create-group': {
      createSelectionGroup()
      break
    }
    case 'createModule': {
      showModuleDialog()
      break
    }
    case 'openModule': {
      if (currentCell.value) {
        openModule(currentCell.value.id)
      }
      break
    }
    case 'rotateClockwise': {
      // 计算旋转中心
      if (selectedCells.length > 0) {
        const bbox = graphRef.value.getCellsBBox(selectedCells)
        if (bbox) {
          const centerX = bbox.x + bbox.width / 2
          const centerY = bbox.y + bbox.height / 2
          selectedCells.forEach((cell) => {
            if (cell.isNode()) {
              const node = cell as Node
              const rotation = node.getAngle() || 0
              node.rotate(rotation + 90, { center: { x: centerX, y: centerY } })
            }
          })
        }
      } else if (currentCell.value && currentCell.value.isNode()) {
        const node = currentCell.value as Node
        const rotation = node.getAngle() || 0
        const bbox = node.getBBox()
        const centerX = bbox.x + bbox.width / 2
        const centerY = bbox.y + bbox.height / 2
        node.rotate(rotation + 90, { center: { x: centerX, y: centerY } })
      }
      break
    }
    case 'rotateCounterClockwise': {
      // 计算旋转中心
      if (selectedCells.length > 0) {
        const bbox = graphRef.value.getCellsBBox(selectedCells)
        if (bbox) {
          const centerX = bbox.x + bbox.width / 2
          const centerY = bbox.y + bbox.height / 2
          selectedCells.forEach((cell) => {
            if (cell.isNode()) {
              const node = cell as Node
              const rotation = node.getAngle() || 0
              node.rotate(rotation - 90, { center: { x: centerX, y: centerY } })
            }
          })
        }
      } else if (currentCell.value && currentCell.value.isNode()) {
        const node = currentCell.value as Node
        const rotation = node.getAngle() || 0
        const bbox = node.getBBox()
        const centerX = bbox.x + bbox.width / 2
        const centerY = bbox.y + bbox.height / 2
        node.rotate(rotation - 90, { center: { x: centerX, y: centerY } })
      }
      break
    }
    case 'undo': {
      graphRef.value.undo()
      break
    }
    case 'redo': {
      graphRef.value.redo()
      break
    }
    case 'editLabel': {
      if (currentCell.value && currentCell.value.isEdge()) {
        const edge = currentCell.value
        edge.addTools({
          name: 'edge-editor',
          args: {
            attrs: {
              backgroundColor: '#FFF',
            },
          },
        })
      }
      break
    }
    // 新增画布菜单选项处理
    case 'paste': {
      if (!graphRef.value.isClipboardEmpty()) {
        const cells = graphRef.value.paste({ offset: 32 })
        graphRef.value.cleanSelection()
        graphRef.value.select(cells)
      }
      break
    }
    case 'zoom-in': {
      if (graphRef.value) {
        const zoom = graphRef.value.zoom()
        if (zoom < 10) {
          graphRef.value.zoom(0.1)
        }
      }
      break
    }
    case 'zoom-out': {
      if (graphRef.value) {
        const zoom = graphRef.value.zoom()
        if (zoom > 0.1) {
          graphRef.value.zoom(-0.1)
        }
      }
      break
    }
    case 'fit-view': {
      if (graphRef.value) {
        graphRef.value.zoomToFit({ padding: 20 })
      }
      break
    }
    case 'actual-size': {
      if (graphRef.value) {
        graphRef.value.zoomTo(1)
        currentZoom.value = 100
        graphRef.value.centerContent()
      }
      break
    }
    case 'select-all': {
      if (graphRef.value) {
        const nodes = graphRef.value.getNodes()
        if (nodes) {
          graphRef.value.select(nodes)
        }
      }
      break
    }
    case 'export-svg': {
      if (graphRef.value) {
        // 获取画布中所有节点和边
        const allNodes = graphRef.value.getNodes()
        const allEdges = graphRef.value.getEdges()
        const allCells = [...allNodes, ...allEdges]

        // 检查画布是否为空，如果为空则提示无法导出
        if (allCells.length === 0) {
          ElMessage.warning('画布为空，无法导出SVG图片')
          return
        }

        exportSelectedNodesAsSVG()
      }
      break
    }
    case 'export-json': {
      if (graphRef.value) {
        exportAsJSON()
      }
      break
    }
  }

  // 关闭右键菜单
  contextMenuVisible.value = false

  // 保存画布状态到当前图纸
  saveGraphContent()
}

// 旋转节点
const rotateNode = (cell: any, angle: number) => {
  if (cell.isNode && cell.isNode()) {
    try {
      // 尝试相对旋转方法
      cell.rotate(angle, { absolute: false })
    } catch (error) {
      console.error('旋转方法错误，尝试替代方案', error)
      // 备选方案1：设置绝对角度
      try {
        const currentAngle = cell.getAngle() || 0
        cell.setAngle((currentAngle + angle + 360) % 360)
      } catch (error) {
        console.error('替代旋转方法也失败', error)
        // 备选方案2：通过attr设置
        try {
          cell.attr('body/transform', `rotate(${angle})`, { absolute: false })
        } catch (error) {
          console.error('所有旋转方法均失败', error)
        }
      }
    }
  }
}

// 关闭上下文菜单
const closeContextMenu = () => {
  contextMenuVisible.value = false
  graphRef.value?.enableSelection()
}

// 打开图片上传对话框
const openImageUploadDialog = () => {
  if (!currentCell.value || !currentCell.value.isNode()) {
    ElMessage.warning('请先选择一个节点')
    return
  }

  // 重置状态
  selectedImageFile.value = null
  selectedImagePreview.value = ''

  // 显示对话框
  imageUploadDialogVisible.value = true

  // 关闭右键菜单
  closeContextMenu()
}

// 触发文件选择
const triggerImageFileSelect = () => {
  imageFileInputRef.value?.click()
}

// 处理文件选择
const handleImageFileSelect = (event: Event) => {
  const target = event.target as HTMLInputElement
  const file = target.files?.[0]

  if (file) {
    if (!file.type.startsWith('image/')) {
      ElMessage.error('请选择图片文件')
      return
    }

    selectedImageFile.value = file

    // 创建预览
    const reader = new FileReader()
    reader.addEventListener('load', (e) => {
      selectedImagePreview.value = e.target?.result as string
    })
    reader.readAsDataURL(file)
  }
}

// 应用图片到节点
const applyImageToNode = () => {
  if (!selectedImageFile.value || !currentCell.value || !currentCell.value.isNode()) {
    return
  }

  const node = currentCell.value as Node
  const reader = new FileReader()

  reader.addEventListener('load', (e) => {
    const imageUrl = e.target?.result as string

    // 获取节点尺寸
    const size = node.getSize()

    // 获取或创建节点的markup，添加覆盖图片
    const currentMarkup = node.getMarkup() || []
    const markupArray = Array.isArray(currentMarkup) ? currentMarkup : []

    // 移除之前添加的覆盖图片（如果存在）
    const filteredMarkup = markupArray.filter((item: any) => item.selector !== 'coverImage')

    // 添加新的覆盖图片元素
    const newMarkup = [
      ...filteredMarkup,
      {
        tagName: 'image',
        selector: 'coverImage',
      },
    ]

    // 设置新的markup
    node.setMarkup(newMarkup)

    // 检查是否是模块节点
    const nodeData = node.getData()
    const isModuleNode = nodeData?.isModule || node.shape === 'module-node'

    // 设置图片属性，让图片完全覆盖节点
    node.attr({
      coverImage: {
        width: size.width,
        height: size.height,
        x: 0,
        y: 0,
        href: imageUrl,
        preserveAspectRatio: 'xMidYMid meet', // 改为meet以保持图片比例并完整显示
        style: 'pointer-events: none; z-index: 10;',
      },
    })

    if (isModuleNode) {
      // 模块节点保持边框和标签可见
      node.attr({
        body: {
          fill: 'rgba(255, 255, 255, 0.1)', // 半透明白色，让图片稍微透出
          stroke: '#5F95FF',
          strokeWidth: 2,
          rx: 5,
          ry: 5,
        },
        label: {
          // 确保标签在图片之上
          style: {
            visibility: 'visible',
            display: 'block',
            opacity: '1',
            zIndex: '15',
          },
          fill: '#fff',
          fontSize: 14,
          fontWeight: 'bold',
          // 添加文字阴影以提高可读性
          textShadow: '1px 1px 2px rgba(0,0,0,0.8)',
        },
      })
    } else {
      // 普通节点隐藏原始的body，让图片完全遮盖
      node.attr({
        body: {
          fill: 'transparent',
          stroke: 'transparent',
          strokeWidth: 0,
        },
      })
    }

    // 确保连接桩在图片之上并且可见
    node.getPorts().forEach((port) => {
      node.portProp(port.id as string, 'attrs/circle', {
        fill: '#fff',
        stroke: '#31d0c6',
        strokeWidth: 2,
        r: 4,
        // 确保连接桩在最上层
        style: 'pointer-events: all; z-index: 20; cursor: crosshair;',
      })
    })

    // 存储图片信息到节点数据中，便于后续操作
    node.setData({
      ...node.getData(),
      hasCustomImage: true,
      imageUrl,
    })

    // 如果是模块节点，更新模块数据中的图片信息
    if (isModuleNode) {
      const drawingModules = modules.value.get(activeDrawingId.value)
      if (drawingModules && drawingModules.has(node.id)) {
        const moduleData = drawingModules.get(node.id)
        if (moduleData) {
          moduleData.hasCustomImage = true
          moduleData.imageUrl = imageUrl
          // 更新模块数据
          drawingModules.set(node.id, moduleData)
        }
      }
    }

    // 关闭对话框
    imageUploadDialogVisible.value = false
    ElMessage.success('图片已覆盖节点，连接桩保持可用')
  })

  reader.readAsDataURL(selectedImageFile.value)
}

// 更新节点图片尺寸（节点缩放时调用）
const updateNodeImageSize = (node: Node, size: { width: number; height: number }) => {
  const nodeId = node.id as string

  // 清除之前的防抖定时器
  const existingTimeout = imageUpdateTimeouts.get(nodeId)
  if (existingTimeout) {
    clearTimeout(existingTimeout)
  }

  // 设置新的防抖定时器
  const timeout = setTimeout(() => {
    try {
      // 获取节点数据以保持图片URL
      const nodeData = node.getData()
      const imageUrl = nodeData?.imageUrl

      if (!imageUrl) {
        return
      }

      // 获取当前coverImage属性
      const currentImageAttrs = node.attr('coverImage') || {}

      // 更新覆盖图片的尺寸，保持原有属性
      node.attr({
        coverImage: {
          ...currentImageAttrs,
          width: size.width,
          height: size.height,
          x: 0,
          y: 0,
          href: imageUrl,
          preserveAspectRatio: 'xMidYMid meet', // 改为meet以保持图片比例并完整显示
          style: 'pointer-events: none; z-index: 10;',
        },
      })

      // 确保连接桩仍然在正确位置和层级
      node.getPorts().forEach((port) => {
        node.portProp(port.id as string, 'attrs/circle', {
          fill: '#fff',
          stroke: '#31d0c6',
          strokeWidth: 2,
          r: 4,
          style: 'pointer-events: all; z-index: 20; cursor: crosshair;',
        })
      })

      // 清除timeout记录
      imageUpdateTimeouts.delete(nodeId)
    } catch (error) {
      console.error('更新节点图片尺寸失败:', error)
    }
  }, 50) // 50ms防抖延迟

  // 记录timeout
  imageUpdateTimeouts.set(nodeId, timeout)
}

// 移除节点上的图片
const removeImageFromNode = () => {
  if (!currentCell.value || !currentCell.value.isNode()) {
    ElMessage.warning('请先选择一个节点')
    return
  }

  const node = currentCell.value as Node
  const nodeData = node.getData()

  // 检查节点是否有自定义图片
  if (!nodeData?.hasCustomImage) {
    ElMessage.info('该节点没有自定义图片')
    return
  }

  // 获取当前markup并移除覆盖图片
  const currentMarkup = node.getMarkup() || []
  const markupArray = Array.isArray(currentMarkup) ? currentMarkup : []
  const filteredMarkup = markupArray.filter((item: any) => item.selector !== 'coverImage')

  // 设置新的markup
  node.setMarkup(filteredMarkup)

  // 检查是否是模块节点
  const isModuleNode = nodeData?.isModule || node.shape === 'module-node'

  // 恢复原始节点样式
  if (isModuleNode) {
    // 恢复模块节点的原始样式
    node.attr({
      body: {
        fill: '#FFFFFF',
        stroke: '#5F95FF',
        strokeWidth: 2,
        rx: 5,
        ry: 5,
      },
      label: {
        // 恢复标签样式
        fill: '#333333',
        fontSize: 14,
        fontWeight: 'bold',
        textShadow: 'none',
        style: {
          visibility: 'visible',
          display: 'block',
          opacity: '1',
        },
      },
    })
  } else {
    // 普通节点恢复默认样式
    node.attr({
      body: {
        fill: '#f0f0f0',
        stroke: '#333',
        strokeWidth: 1,
      },
    })
  }

  // 移除覆盖图片属性（通过设置为undefined）
  node.attr('coverImage', {})

  // 更新节点数据
  node.setData({
    ...nodeData,
    hasCustomImage: false,
    imageUrl: undefined,
  })

  // 如果是模块节点，更新模块数据
  if (isModuleNode) {
    const drawingModules = modules.value.get(activeDrawingId.value)
    if (drawingModules && drawingModules.has(node.id)) {
      const moduleData = drawingModules.get(node.id)
      if (moduleData) {
        moduleData.hasCustomImage = false
        moduleData.imageUrl = undefined
        // 更新模块数据
        drawingModules.set(node.id, moduleData)
      }
    }
  }

  // 关闭右键菜单
  closeContextMenu()

  ElMessage.success('图片已移除')
}



// 当前缩放级别
const currentZoom = ref(100) // 100% is default

// 处理右键菜单事件
const handleGraphContextMenu = (e: Event) => {
  e.preventDefault()
  e.stopPropagation()
  return false
}

// 处理文档右键菜单事件
const handleDocumentContextMenu = (e: Event) => {
  if (e.target instanceof Element && (e.target.closest('#graph-container') || e.target.closest('.center-content'))) {
    e.preventDefault()
    e.stopPropagation()
    return false
  }
}

// 注册鼠标右键事件处理
const setupContextMenu = () => {
  // 阻止默认右键菜单，使用X6的内置平移功能
  const graphContainer = document.getElementById('graph-container')
  if (graphContainer) {
    graphContainer.addEventListener('contextmenu', handleGraphContextMenu)
  }

  // 阻止整个文档的右键菜单，防止浏览器的前进后退
  document.addEventListener('contextmenu', handleDocumentContextMenu)
}

// 监听键盘状态
const handleKeyDown = (e: KeyboardEvent) => {
  // 如果在输入框中，不处理快捷键
  const target = e.target as HTMLElement
  if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.contentEditable === 'true') {
    return
  }

  if (e.key === 'Control') {
    ctrlKeyPressed.value = true
    // 当按下Ctrl键且拖动按钮开启时，添加panning-mode类来显示手形光标
    const graphContainer = document.getElementById('graph-container')
    if (graphContainer && referenceStandardsVisible.value) {
      graphContainer.classList.add('panning-mode')
    }
  } else if (e.key === ' ') {
    e.preventDefault() // 防止页面滚动
    spaceKeyPressed.value = true

    // 空格键可以临时启用平移模式
    if (graphRef.value) {
      graphRef.value.enablePanning()
      const graphContainer = document.getElementById('graph-container')
      if (graphContainer) {
        graphContainer.classList.add('panning-mode')
      }
    }
  }
}

const handleKeyUp = (e: KeyboardEvent) => {
  if (e.key === 'Control') {
    ctrlKeyPressed.value = false
    // 当释放Ctrl键时，移除panning-mode类，恢复默认鼠标样式
    const graphContainer = document.getElementById('graph-container')
    if (graphContainer) {
      graphContainer.classList.remove('panning-mode')
    }
  } else if (e.key === ' ') {
    spaceKeyPressed.value = false

    // 空格键释放时，如果拖动按钮关闭，则禁用平移
    if (graphRef.value && !referenceStandardsVisible.value) {
      graphRef.value.disablePanning()
      const graphContainer = document.getElementById('graph-container')
      if (graphContainer) {
        graphContainer.classList.remove('panning-mode')
      }
    }
  }
}

// 定义鼠标事件处理函数
const handleMouseDown = () => {
  // 鼠标按下时不需要特殊处理
  // CSS的:active伪类会自动处理按下状态的样式
}

const handleMouseUp = () => {
  // 鼠标释放时不需要特殊处理
  // 通过CSS类控制鼠标样式更加可靠
}

// 设置基本的事件处理
const setupBasicEvents = () => {
  // 添加双击重置视图功能
  const graphContainer = document.getElementById('graph-container')
  if (graphContainer) {
    graphContainer.addEventListener('dblclick', (e) => {
      // 如果按住Ctrl键双击，重置视图到100%并居中
      if (ctrlKeyPressed.value) {
        e.preventDefault()
        resetView()
      }
    })

    // 添加鼠标按下和释放事件
    graphContainer.addEventListener('mousedown', handleMouseDown)
    graphContainer.addEventListener('mouseup', handleMouseUp)
  }

  // 设置右键菜单处理
  setupContextMenu()
}

// 重置视图到默认状态
const resetView = () => {
  if (graphRef.value) {
    // 重置缩放到100%
    graphRef.value.zoomTo(1)
    currentZoom.value = 100

    // 居中内容
    graphRef.value.centerContent()

    ElMessage.success('视图已重置')
  }
}

// 获取可用的输入连接桩
const availableInputPorts = computed(() => {
  // 依赖于更新触发器以确保响应式更新
  nodesUpdateTrigger.value
  // 依赖于选中的边以便在边的源/目标改变时更新
  selectedEdge.value

  if (!graphRef.value) return []

  const ports: { id: string; label: string }[] = []
  const nodes = graphRef.value.getNodes()

  // 获取当前选中边的目标节点ID，避免将边连接到其目标节点
  let excludeNodeId: string | null = null
  if (selectedEdge.value) {
    const target = selectedEdge.value.getTarget()
    if (target && typeof target === 'object' && 'cell' in target) {
      excludeNodeId = target.cell as string
    }
  }

  nodes.forEach(node => {
    // 如果是要排除的节点，跳过
    if (excludeNodeId && node.id === excludeNodeId) {
      return
    }

    const nodePorts = node.getPorts()
    const nodeLabel = node.attr('text/text') || node.attr('label/text') || node.id

    nodePorts.forEach(port => {
      // 获取端口的配置信息
      const portGroup = port.group || 'unknown'
      const nodeData = node.getData() || {}
      const nodeConfig = nodeData.nodeConfiguration || {}
      const dynamicPinConfig = nodeConfig.dynamicPinConfig || {}

      // 判断是否为输入端口的逻辑：
      // 1. 端口在左侧或上方（传统输入位置）
      // 2. 或者节点配置明确指定为输入类型
      const isInputPort = portGroup === 'left' || portGroup === 'top' ||
                         dynamicPinConfig.defaultPinType === 'input' ||
                         (portGroup === 'customPorts' && dynamicPinConfig.defaultPinType === 'input')

      if (isInputPort) {
        // 获取端口的显示文本
        const portText = node.getPortProp(port.id, 'attrs/text/text') || port.id
        const displayText = portText && portText !== port.id ? ` (${portText})` : ''

        ports.push({
          id: `${node.id}:${port.id}`,
          label: `${nodeLabel} - ${port.id}${displayText}`
        })
      }
    })
  })

  return ports
})

// 获取可用的输出连接桩
const availableOutputPorts = computed(() => {
  // 依赖于更新触发器以确保响应式更新
  nodesUpdateTrigger.value
  // 依赖于选中的边以便在边的源/目标改变时更新
  selectedEdge.value

  if (!graphRef.value) return []

  const ports: { id: string; label: string }[] = []
  const nodes = graphRef.value.getNodes()

  // 获取当前选中边的源节点ID，避免将边连接到其源节点
  let excludeNodeId: string | null = null
  if (selectedEdge.value) {
    const source = selectedEdge.value.getSource()
    if (source && typeof source === 'object' && 'cell' in source) {
      excludeNodeId = source.cell as string
    }
  }

  nodes.forEach(node => {
    // 如果是要排除的节点，跳过
    if (excludeNodeId && node.id === excludeNodeId) {
      return
    }

    const nodePorts = node.getPorts()
    const nodeLabel = node.attr('text/text') || node.attr('label/text') || node.id

    nodePorts.forEach(port => {
      // 获取端口的配置信息
      const portGroup = port.group || 'unknown'
      const nodeData = node.getData() || {}
      const nodeConfig = nodeData.nodeConfiguration || {}
      const dynamicPinConfig = nodeConfig.dynamicPinConfig || {}

      // 判断是否为输出端口的逻辑：
      // 1. 端口在右侧或下方（传统输出位置）
      // 2. 或者节点配置明确指定为输出类型
      const isOutputPort = portGroup === 'right' || portGroup === 'bottom' ||
                          dynamicPinConfig.defaultPinType === 'output' ||
                          (portGroup === 'customPorts' && dynamicPinConfig.defaultPinType === 'output') ||
                          // 如果没有明确指定类型，右侧和下方默认为输出
                          (portGroup !== 'left' && portGroup !== 'top' && !dynamicPinConfig.defaultPinType)

      if (isOutputPort) {
        // 获取端口的显示文本
        const portText = node.getPortProp(port.id, 'attrs/text/text') || port.id
        const displayText = portText && portText !== port.id ? ` (${portText})` : ''

        ports.push({
          id: `${node.id}:${port.id}`,
          label: `${nodeLabel} - ${port.id}${displayText}`
        })
      }
    })
  })

  return ports
})

// 更新边的属性值
const updateEdgeProperties = (edge: any) => {
  if (!edge) return

  // 获取边的源和目标连接信息
  const source = edge.getSource()
  const target = edge.getTarget()

  if (source && typeof source === 'object' && 'cell' in source && 'port' in source) {
    edgeSourcePort.value = `${source.cell}:${source.port}`
  } else {
    edgeSourcePort.value = ''
  }

  if (target && typeof target === 'object' && 'cell' in target && 'port' in target) {
    edgeTargetPort.value = `${target.cell}:${target.port}`
  } else {
    edgeTargetPort.value = ''
  }

  // 获取边的路由类型
  const router = edge.getRouter()
  if (router && router.name === 'orth') {
    edgeRouterType.value = '正交'
  } else {
    edgeRouterType.value = '无'
  }

  // 获取边的连接器类型
  const connector = edge.getConnector()
  if (connector && connector.name === 'rounded') {
    edgeConnectorType.value = '圆角'
  } else if (connector && connector.name === 'smooth') {
    edgeConnectorType.value = '平滑'
  } else {
    edgeConnectorType.value = '无'
  }

  // 获取边的样式属性
  edgeStrokeColor.value = edge.attr('line/stroke') || '#000000'
  edgeStrokeWidth.value = edge.attr('line/strokeWidth') || 2

  // 获取标签的填充和文本颜色
  const labelAttrs = edge.getLabels()[0]?.attrs || {}
  edgeFillColor.value = labelAttrs.rect?.fill || '#ffffff'
  edgeTextColor.value = labelAttrs.text?.fill || '#333333'
  edgeFontFamily.value = labelAttrs.text?.fontFamily || 'Arial'
  edgeFontSize.value = labelAttrs.text?.fontSize || 12
}

// 更新边的源端连接桩
const updateEdgeSourcePort = (value: string) => {
  if (!selectedEdge.value || !value) return

  const [nodeId, portId] = value.split(':')
  if (nodeId && portId) {
    selectedEdge.value.setSource({ cell: nodeId, port: portId })
    // 同步更新响应式变量
    edgeSourcePort.value = value
  }
}

// 更新边的目标端连接桩
const updateEdgeTargetPort = (value: string) => {
  if (!selectedEdge.value || !value) return

  const [nodeId, portId] = value.split(':')
  if (nodeId && portId) {
    selectedEdge.value.setTarget({ cell: nodeId, port: portId })
    // 同步更新响应式变量
    edgeTargetPort.value = value
  }
}

// 更新边的路由类型
const updateEdgeRouterType = (value: string) => {
  if (!selectedEdge.value) return

  if (value === '正交') {
    selectedEdge.value.setRouter({ name: 'orth', args: { padding: -10 } })
  } else {
    selectedEdge.value.setRouter({ name: 'normal', args: { padding: 0 } })
  }
  // 同步更新响应式变量
  edgeRouterType.value = value
}

// 更新边的连接类型
const updateEdgeConnectorType = (value: string) => {
  if (!selectedEdge.value) return

  if (value === '圆角') {
    selectedEdge.value.setConnector({ name: 'rounded', args: { radius: 8 } })
  } else if (value === '平滑') {
    selectedEdge.value.setConnector({ name: 'smooth' })
  } else {
    selectedEdge.value.setConnector({ name: 'normal', args: { radius: 0 } })
  }
  // 同步更新响应式变量
  edgeConnectorType.value = value
}

// 更新边的线条颜色
const updateEdgeStrokeColor = (value: string) => {
  if (!selectedEdge.value) return
  selectedEdge.value.attr('line/stroke', value)
  // 同步更新响应式变量
  edgeStrokeColor.value = value
}

// 更新边的线条宽度
const updateEdgeStrokeWidth = (value: number) => {
  if (!selectedEdge.value) return
  selectedEdge.value.attr('line/strokeWidth', value)
  // 同步更新响应式变量
  edgeStrokeWidth.value = value
}

// 更新边的填充颜色（标签背景）
const updateEdgeFillColor = (value: string) => {
  if (!selectedEdge.value) return

  const labels = selectedEdge.value.getLabels()
  if (labels.length > 0) {
    selectedEdge.value.setLabelAt(0, {
      ...labels[0],
      attrs: {
        ...labels[0].attrs,
        rect: {
          ...labels[0].attrs?.rect,
          fill: value
        }
      }
    })
  }
  // 同步更新响应式变量
  edgeFillColor.value = value
}

// 更新边的文本颜色
const updateEdgeTextColor = (value: string) => {
  if (!selectedEdge.value) return

  const labels = selectedEdge.value.getLabels()
  if (labels.length > 0) {
    selectedEdge.value.setLabelAt(0, {
      ...labels[0],
      attrs: {
        ...labels[0].attrs,
        text: {
          ...labels[0].attrs?.text,
          fill: value
        }
      }
    })
  }
  // 同步更新响应式变量
  edgeTextColor.value = value
}

// 更新边的字体
const updateEdgeFontFamily = (value: string) => {
  if (!selectedEdge.value) return

  const labels = selectedEdge.value.getLabels()
  if (labels.length > 0) {
    selectedEdge.value.setLabelAt(0, {
      ...labels[0],
      attrs: {
        ...labels[0].attrs,
        text: {
          ...labels[0].attrs?.text,
          fontFamily: value
        }
      }
    })
  }
  // 同步更新响应式变量
  edgeFontFamily.value = value
}

// 更新边的字体大小
const updateEdgeFontSize = (value: number) => {
  if (!selectedEdge.value) return

  const labels = selectedEdge.value.getLabels()
  if (labels.length > 0) {
    selectedEdge.value.setLabelAt(0, {
      ...labels[0],
      attrs: {
        ...labels[0].attrs,
        text: {
          ...labels[0].attrs?.text,
          fontSize: value
        }
      }
    })
  }
  // 同步更新响应式变量
  edgeFontSize.value = value
}

// 恢复边的格式属性
const restoreEdgeProperties = () => {
    if (!graphRef.value) return

  try {
    const edges = graphRef.value.getEdges()

    edges.forEach(edge => {
      // 从边的导入数据中查找edgeProperties
      const cells = graphRef.value?.getCells() || []
      const edgeCell = cells.find(cell => cell.id === edge.id)
      let edgeProperties = null

      if (edgeCell) {
        // 首先尝试从cell的JSON数据中获取
        const cellJSON = edgeCell.toJSON()
        edgeProperties = cellJSON.edgeProperties

        // 如果有edgeProperties，存储到边的data中
        if (edgeProperties) {
          edge.setData({ ...edge.getData(), edgeProperties })
        }
      }

      // 如果没有从cell中找到，尝试从data中获取
      if (!edgeProperties) {
        const edgeData = edge.getData()
        edgeProperties = edgeData?.edgeProperties
      }

      if (edgeProperties) {
        // 恢复路由类型
        if (edgeProperties.routerType === '正交') {
          edge.setRouter({ name: 'orth', args: { padding: -10 } })
        } else {
          edge.setRouter({ name: 'normal', args: { padding: 0 } })
        }

        // 恢复连接类型
        if (edgeProperties.connectorType === '圆角') {
          edge.setConnector({ name: 'rounded', args: { radius: 8 } })
        } else if (edgeProperties.connectorType === '平滑') {
          edge.setConnector({ name: 'smooth' })
        } else {
          edge.setConnector({ name: 'normal', args: { radius: 0 } })
        }

        // 恢复线条样式
        if (edgeProperties.strokeColor) {
          edge.attr('line/stroke', edgeProperties.strokeColor)
        }
        if (edgeProperties.strokeWidth !== undefined) {
          edge.attr('line/strokeWidth', edgeProperties.strokeWidth)
        }

        // 恢复标签样式
        const labels = edge.getLabels()
        if (labels.length > 0 && (edgeProperties.fillColor || edgeProperties.textColor || edgeProperties.fontFamily || edgeProperties.fontSize)) {
          edge.setLabelAt(0, {
            ...labels[0],
            attrs: {
              ...labels[0].attrs,
              rect: {
                ...labels[0].attrs?.rect,
                ...(edgeProperties.fillColor && { fill: edgeProperties.fillColor })
              },
              text: {
                ...labels[0].attrs?.text,
                ...(edgeProperties.textColor && { fill: edgeProperties.textColor }),
                ...(edgeProperties.fontFamily && { fontFamily: edgeProperties.fontFamily }),
                ...(edgeProperties.fontSize !== undefined && { fontSize: edgeProperties.fontSize })
              }
            }
          })
        }
      }
    })

    console.log('边的格式属性恢复完成')
  } catch (error) {
    console.error('恢复边的格式属性时出错:', error)
  }
}

// 保存当前画布数据到localStorage
const saveCurrentDrawing = () => {
  if (!graphRef.value || !activeDrawingId.value) {
    console.warn('无法保存：图表引用或活动图纸ID不存在')
    return
  }

  try {
    // 获取当前画布内容
    const currentContent = graphRef.value.toJSON()

    // 获取当前画布的所有模块数据
    const drawingModules = modules.value.get(activeDrawingId.value)

    // 构建保存数据
    const saveData = {
      drawingId: activeDrawingId.value,
      content: currentContent,
      modules: drawingModules ? Object.fromEntries(drawingModules) : {},
      properties: {
        backgroundColor: backgroundColor.value,
        gridType: gridType.value,
        gridColor: gridColor.value,
        pageLineVisible: pageLineVisible.value,
        referenceStandardsVisible: referenceStandardsVisible.value,
        elementsStandard: elementsStandard.value,
        guidelineStandard: guidelineStandard.value,
        canvasWidth: canvasWidth.value,
        canvasHeight: canvasHeight.value,
        baseCanvasWidth: baseCanvasWidth.value,
        baseCanvasHeight: baseCanvasHeight.value,
      },
      lastSaved: new Date().toISOString(),
    }

    // 保存到localStorage
    localStorage.setItem(`x6-drawing-${activeDrawingId.value}`, JSON.stringify(saveData))

    ElMessage.success('画布数据已保存')
    console.log('画布数据保存成功:', { drawingId: activeDrawingId.value })
  } catch (error) {
    console.error('保存画布数据失败:', error)
    ElMessage.error('保存失败，请重试')
  }
}

// 设置键盘快捷键
const setupKeyboardShortcuts = () => {
  const handleKeyDown = (e: KeyboardEvent) => {
    // Ctrl + S 保存
    if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 's') {
      e.preventDefault() // 阻止浏览器默认保存行为
      saveCurrentDrawing()
    }
  }

  // 添加事件监听
  globalThis.addEventListener('keydown', handleKeyDown)

  // 在组件卸载时移除事件监听
  onUnmounted(() => {
    globalThis.removeEventListener('keydown', handleKeyDown)
  })
}

onMounted(() => {
  // 确保画布初始化时显示默认鼠标样式
  const graphContainer = document.getElementById('graph-container')
  if (graphContainer) {
    graphContainer.classList.remove('panning-mode')
  }

  // 设置键盘快捷键
  setupKeyboardShortcuts()

  // 检查localStorage中是否有保存的画布数据
  const savedDrawingData = localStorage.getItem(`x6-drawing-${activeDrawingId.value}`)
  if (savedDrawingData) {
    try {
      const parsedData = JSON.parse(savedDrawingData)

      // 恢复画布内容
      if (graphRef.value && parsedData.content) {
        // 延迟加载以确保graph实例已完全初始化
        nextTick(() => {
          if (graphRef.value) {
            graphRef.value.fromJSON(parsedData.content)
            console.log('成功恢复画布内容')
          }
        })
      }

      // 恢复画布属性
      if (parsedData.properties) {
        backgroundColor.value = parsedData.properties.backgroundColor
        gridType.value = parsedData.properties.gridType
        gridColor.value = parsedData.properties.gridColor
        pageLineVisible.value = parsedData.properties.pageLineVisible
        referenceStandardsVisible.value = parsedData.properties.referenceStandardsVisible
        elementsStandard.value = parsedData.properties.elementsStandard
        guidelineStandard.value = parsedData.properties.guidelineStandard
        canvasWidth.value = parsedData.properties.canvasWidth
        canvasHeight.value = parsedData.properties.canvasHeight
        baseCanvasWidth.value = parsedData.properties.baseCanvasWidth
        baseCanvasHeight.value = parsedData.properties.baseCanvasHeight
      }

      // 恢复模块数据
      if (parsedData.modules) {
        const drawingModules = new Map()
        for (const [moduleId, moduleData] of Object.entries(parsedData.modules)) {
          drawingModules.set(moduleId, moduleData)
        }
        modules.value.set(activeDrawingId.value, drawingModules)
      }
    } catch {
      // console.error('加载保存的画布数据失败:', error)
    }
  }

  // 检查localStorage中是否有保存的模块数据，如果有则加载
  const modulesStr = localStorage.getItem('x6-modules')
  if (modulesStr) {
    try {
      const modulesData = JSON.parse(modulesStr)

      // 将普通对象转换回Map结构
      for (const drawingId in modulesData) {
        const drawingModules = new Map()

        for (const moduleId in modulesData[drawingId]) {
          drawingModules.set(moduleId, modulesData[drawingId][moduleId])
        }

        modules.value.set(Number(drawingId), drawingModules)
      }

      // 清除localStorage中的数据，避免重复加载
      localStorage.removeItem('x6-modules')
    } catch (error) {
      console.error('加载模块数据失败:', error)
    }
  }

  // 初始化画布
  //- `Graph` 对象用于初始化流程图画布，`container` 指向 HTML 中 `graph-container` 这个 DOM 元素。流程图支持缩放、连线、拖拽等功能。
  const graph = new Graph({
    container: document.getElementById('graph-container') as HTMLElement,
    autoResize: true,
    grid: {
      visible: true,
      size: 10,
    },
    panning: {
      enabled: referenceStandardsVisible.value, // 根据拖动按钮状态决定是否启用平移
      modifiers: ['ctrl'], // 只有按Ctrl键时才能平移
    },
    mousewheel: {
      enabled: true,
      zoomAtMousePosition: true,
      modifiers: [],
      minScale: 0.2, // 最小缩放到20%
      maxScale: 5, // 最大缩放到500%
      factor: 1.2, // 缩放因子，每次20%增减
      global: false, // 在整个画布区域生效
    },
    // keyboard: {
    //   enabled: true,
    //   global: true,
    // },
    connecting: {
      router: {
        name: 'orth', // 使用normal路由器创建直线连接
        args: {
          padding: -10, // 设置padding为0
        },
      },
      connector: {
        name: 'normal', // 保持normal连接器
        args: {
          radius: 0, // 移除圆角，使连接线完全直线化
          padding: 0, // 设置padding为0
        },
      },
      // anchor: 'center',
      connectionPoint: 'anchor',
      allowBlank: true,

      //高亮所有可连接的边或连接桩
      // highlight: true,
      snap: {
        radius: 20,
      },
      // 允许创建未连接的边
      allowEdge: true,
      allowNode: true,
      allowPort: true,
      edgeAnchor: {
        name: 'orth',
        args: {
          offset: 0,
          direction: 'auto',
        },
      },
      targetEdgeAnchor: 'orth',
      createEdge() {
        return new Shape.Edge({
          router: {
            name: 'orth',
            args: {
              padding: -10,
            },
          },
          attrs: {
            line: {
              connection: true,
              stroke: '#000000', // 改为黑色
              strokeWidth: 2, // 改为2，与节点线宽一致
              magnet: true,
              // 默认情况下不显示箭头，只有选中时才显示
              // targetMarker: {
              //   name: 'circle', // 使用箭头标记作为默认
              //   width: 8,
              //   height: 8,
              //   attrs: {
              //     stroke: '#000000',
              //     strokeWidth: 2, // 与边的粗细保持一致
              //     fill: '#000000',
              //   },
              // },
              // 移除线头相关样式
              // strokeLinecap: 'butt', // 改为方形端点，不显示圆形线头
              // strokeLinejoin: 'miter', // 改为尖角连接
            },
          },
          zIndex: 0,
          // 添加边的标签配置
          defaultLabel: {
            markup: [
              {
                tagName: 'rect',
                attrs: {
                  fill: '#ffffff',
                  stroke: '#000000', // 改为黑色保持一致
                  strokeWidth: 2, // 与边的粗细保持一致
                  rx: 3,
                  ry: 3,
                },
              },
              {
                tagName: 'text',
                attrs: {
                  fill: '#333333',
                  fontSize: 12,
                  textAnchor: 'middle',
                  textVerticalAnchor: 'middle',
                },
              },
            ],
            position: {
              distance: 0.5, // 标签位置在边的中点
              offset: { x: 0, y: -10 }, // 稍微向上偏移
            },
          },
          // 添加边的工具配置
          tools: [
            {
              name: 'edge-editor', // 启用边的文本编辑工具
              args: {
                attrs: {
                  backgroundColor: '#FFF',
                  borderRadius: 3,
                  padding: '2px 6px',
                  fontSize: 12,
                },
              },
            },
          ],
        })
      },
      validateConnection({ targetMagnet, sourceCell, targetCell, sourcePort, targetPort }: any) {
        // 检查目标磁铁是否存在
        // if (!targetMagnet) {
        //   return false
        // }

        // 修改这里的逻辑：允许边和边之间的连接
        // 检查源和目标单元格是否存在（可以是节点或边）
        if (!sourceCell || !targetCell) {
          return false
        }

        // 防止连接到同一个节点的同一个端口（仅对节点有效）
        if (sourceCell.isNode && targetCell.isNode && sourceCell === targetCell && sourcePort === targetPort) {
          return false
        }

        // 防止连接到同一个节点（可选，如果不需要节点自连接）
        // if (sourceCell === targetCell) {
        //   return false
        // }

        // 防止重复连接 - 检查是否已经存在相同的连接
        try {
          const sourceEdges = graphRef.value?.getConnectedEdges(sourceCell) || []
          const hasExistingConnection = sourceEdges.some((edge: any) => {
            const source = edge.getSource()
            const target = edge.getTarget()

            return (
              (source.cell === sourceCell.id &&
                source.port === sourcePort &&
                target.cell === targetCell.id &&
                target.port === targetPort) ||
              // 检查反向连接（如果需要防止双向重复连接）
              (source.cell === targetCell.id && source.port === targetPort && target.cell === sourceCell.id && target.port === sourcePort)
            )
          })

          if (hasExistingConnection) {
            return false
          }
        } catch (error) {
          console.warn('连接验证时出现错误:', error)
        }

        return true
      },
    },
    highlighting: {
      magnetAdsorbed: {
        name: 'stroke',
        args: {
          attrs: {
            fill: '#5F95FF',
            stroke: '#5F95FF',
            strokeWidth: 3,
            r: 6, // 增大连接点大小
          },
        },
      },
      // 添加连线时显示可用的连接点
      magnetAvailable: {
        name: 'stroke',
        args: {
          attrs: {
            stroke: '#5F95FF',
            strokeWidth: 2,
            fill: '#E6F4FF', // 淡蓝色填充
            r: 6,
          },
        },
      },
      // 添加连接点悬停效果
      default: {
        name: 'stroke',
        args: {
          attrs: {
            stroke: '#FFA940',
            strokeWidth: 2,
          },
        },
      },
    },
  })

  // Store graph reference for property panel controls
  graphRef.value = graph

  // 存储图纸0的初始状态
  graphContents.value.set(0, graph.toJSON())
  // 初始化图纸1和图纸2的状态为空
  graphContents.value.set(1, { cells: [] })
  graphContents.value.set(2, { cells: [] })

  // 初始化图纸属性
  // 为图纸0设置当前属性
  drawingProperties.value.set(0, {
    backgroundColor: backgroundColor.value,
    gridType: gridType.value,
    gridColor: gridColor.value,
    pageLineVisible: pageLineVisible.value,
    referenceStandardsVisible: referenceStandardsVisible.value,
    elementsStandard: elementsStandard.value,
    guidelineStandard: guidelineStandard.value,
    canvasWidth: canvasWidth.value,
    canvasHeight: canvasHeight.value,
    baseCanvasWidth: canvasWidth.value,
    baseCanvasHeight: canvasHeight.value,
  })
  // 为图纸1和图纸2设置默认属性
  // drawingProperties.value.set(1, { ...defaultProperties })
  // drawingProperties.value.set(2, { ...defaultProperties })

  // 插件配置
  //- 通过 `.use()` 方法注册了多个插件，包括 `Transform`（支持调整大小、旋转）、`Selection`（选择功能）、`Snapline`（自动对齐线）、`Keyboard`（键盘支持）等。

  graph
    .use(
      new Transform({
        resizing: {
          enabled: true,
          minWidth: 10,
          minHeight: 10,
          maxWidth: 2000,
          maxHeight: 2000,
          orthogonal: false,
          restrict: false,
          preserveAspectRatio: true, // 关闭保持宽高比，允许自由缩放
        },
        rotating: {
          enabled: true,
          grid: 15, // 每次旋转15度
        },
      })
    )
    .use(
      new Selection({
        enabled: true,
        movable: true,
        rubberband: true, // 启用框选
        rubberEdge: true,
        rubberNode: true,
        showNodeSelectionBox: true, // 启用选择框，用于多选时显示
        showEdgeSelectionBox: false,
        multipleSelectionModifiers: ['ctrl', 'meta'], // 启用Ctrl/Cmd键多选
        strict: false,
        pointerEvents: 'none',
        // 优化选择框性能
        className: 'high-performance-selection',
      })
    )
    .use(new Snapline())
    .use(
      new Keyboard({
        enabled: true,
        global: true,
      })
    )
    .use(new Clipboard())
    .use(new History())
  // .use(
  //   new Scroller({
  //     enabled: true,
  //     pannable: true,
  //     autoResize: true,
  //     pageWidth: canvasWidth.value,
  //     pageHeight: canvasHeight.value,
  //     padding: 0,
  //     pageVisible: true,
  //     pageBreak: true,
  //     autoResizeOptions: {
  //       minWidth: 600,
  //       minHeight: 800,
  //       maxWidth: 2000,
  //       maxHeight: 2000,
  //       padding: 20,
  //     },
  //     background: false,
  //     className: 'graph-scroller',
  //   })
  // )

  // 优化鼠标移动事件处理，提高框选性能
  // 添加CSS样式优化框选性能
  const selectionStyle = document.createElement('style')
  selectionStyle.textContent = `
              .x6-graph-scroller {
          width: 100% !important;
          height: 100% !important;
          position: relative !important;
          left: 0 !important;
          top: 0 !important;
          overflow: hidden !important;
          box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
          border-radius: 8px;
        }
      .x6-graph-scroller-content {
        width:100% !important;
        height:100% !important;
        position: relative !important;
        left: 0 !important;
        top: 0 !important;
      }
      .x6-graph-svg {
        position: absolute !important;
        top: 0 !important;
        left: 0 !important;
        width: 100% !important;
        height: 100% !important;
      }
    /* 优化框选性能的CSS */
    .x6-widget-selection-box {
      will-change: transform;
      pointer-events: none !important;
    }
    .x6-widget-selection-inner {
      pointer-events: none !important;
    }
    .x6-widget-selection {
      pointer-events: none !important;
    }

    /* 单选时隐藏Selection框，只显示Transform框 */
    .single-node-selected .x6-widget-selection-box {
      display: none !important;
    }

    /* 多选时显示Selection框 */
    .multiple-nodes-selected .x6-widget-selection-box {
      display: block !important;
    }

    /* 优化Transform性能 */
    .x6-widget-transform {
      will-change: transform;
      transition: none !important;
    }
    .x6-widget-transform-resize {
      will-change: transform;
      transition: none !important;
    }
    .x6-widget-transform-rotate {
      will-change: transform;
      transition: none !important;
    }

    /* 让边缘标记跟随缩放 */
    .x6-edge path {
      /* 移除 vector-effect: non-scaling-stroke; 让边跟随缩放 */
    }

    .x6-edge-tool-remove path,
    .x6-edge-selected .x6-edge-selection-box {
      vector-effect: non-scaling-stroke;
    }

    /* 提高选择框性能 */
    .x6-widget-selection-rubberband {
      will-change: transform, width, height;
      border: 1px solid #1890ff;
      background-color: rgba(24, 144, 255, 0.2);
      transition: none !important;
    }

    /* 高性能选择类 */
    .high-performance-selection {
      will-change: transform, width, height;
      transition: none !important;
    }

    /* 边的拖拽端点三角形样式 */
    .x6-edge-tool-source-arrowhead polygon,
    .x6-edge-tool-target-arrowhead polygon {
      fill: #1890FF;
      stroke: #FFFFFF;
      stroke-width: 1;
      cursor: move;
    }

    .x6-edge-tool-source-arrowhead:hover polygon,
    .x6-edge-tool-target-arrowhead:hover polygon {
      fill: #40A9FF;
    }

    /* 边的顶点工具样式 */
    .x6-edge-tool-vertices circle {
      fill: #1890FF;
      stroke: #FFFFFF;
      stroke-width: 1;
      cursor: move;
    }

    /* 边选中时的线条样式 */
    .x6-edge.x6-edge-selected path {
      stroke: #000000;
      stroke-width: 2;
    }
  `
  document.head.appendChild(selectionStyle)

  // 移除性能瓶颈的事件处理方式
  const graphContainerEl = document.getElementById('graph-container')

  // 确保初始化时画布位置正确
  setTimeout(() => {
    // 重置可能的偏移
    const centerContent = document.querySelector('.center-content') as HTMLElement
    if (centerContent) {
      centerContent.style.transform = 'translate(0, 0)'
    }

    // 更新SVG元素尺寸和位置
    const svgElement = graphContainerEl?.querySelector('.x6-graph-svg') as SVGElement
    if (svgElement) {
      svgElement.setAttribute('width', '100%')
      svgElement.setAttribute('height', '100%')
    }

    // 更新滚动内容尺寸和位置
    const scrollerContent = graphContainerEl?.querySelector('.x6-graph-scroller-content') as HTMLElement
    if (scrollerContent) {
      scrollerContent.style.width = '100%'
      scrollerContent.style.height = '100%'
      scrollerContent.style.left = '0'
      scrollerContent.style.top = '0'
    }

    // 居中画布内容
    if (graphRef.value) {
      graphRef.value.centerContent()
    }
  }, 100)

  // 初始化 stencil
  //- `Stencil` 是用于提供左侧工具栏的组件，用户可以从工具栏中拖拽图形到画布中。支持基本图形和系统设计图的两类分组
  // 创建Stencil实例的函数
  let stencil: any = null

  const createStencil = () => {
    if (stencilGroupsFromJSON.value.length > 0) {
      // 过滤掉"连接桩"组，主页面不显示连接桩组
      const filteredGroups = stencilGroupsFromJSON.value.filter((group) => group.title !== '自定义连接桩')

      stencil = new Stencil({
        title: '流程图',
        target: graph,
        stencilGraphWidth: 240,
        stencilGraphHeight: 180,
        collapsable: true,
        groups: filteredGroups,
        layoutOptions: { columns: 2, columnWidth: 'auto', rowHeight: 'auto' },
      })

      document.getElementById('stencil')?.appendChild(stencil.container)
      // console.log('主页面Stencil创建成功，组数量:', filteredGroups.length, '(已过滤连接桩组)')
      return stencil
    } else {
      return null
    }
  }
  // #region 快捷键与事件
  graph.bindKey(['meta+c', 'ctrl+c'], () => {
    const cells = graph.getSelectedCells()
    if (cells.length > 0) {
      graph.copy(cells)
    }
    return false
  })
  graph.bindKey(['meta+x', 'ctrl+x'], () => {
    const cells = graph.getSelectedCells()
    if (cells.length > 0) {
      graph.cut(cells)
    }
    return false
  })
  graph.bindKey(['meta+v', 'ctrl+v'], () => {
    if (!graph.isClipboardEmpty()) {
      const cells = graph.paste({ offset: 32 })
      graph.cleanSelection()
      graph.select(cells)
    }
    return false
  })

  // undo redo
  graph.bindKey(['meta+z', 'ctrl+z'], () => {
    if (graph.canUndo()) {
      graph.undo()
    }
    return false
  })
  graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
    if (graph.canRedo()) {
      graph.redo()
    }
    return false
  })

  // select all
  graph.bindKey(['meta+a', 'ctrl+a'], () => {
    const nodes = graph.getNodes()
    if (nodes) {
      graph.select(nodes)
    }
  })

  // delete
  graph.bindKey('backspace', () => {
    const cells = graph.getSelectedCells()
    if (cells.length > 0) {
      graph.removeCells(cells)
    }
  })

  // 同样支持DELETE键
  graph.bindKey('delete', () => {
    const cells = graph.getSelectedCells()
    if (cells.length > 0) {
      graph.removeCells(cells)
    }
  })

  // zoom
  graph.bindKey(['ctrl+1', 'meta+1'], () => {
    const zoom = graph.zoom()
    if (zoom < 1.5) {
      graph.zoom(0.1)
    }
  })
  graph.bindKey(['ctrl+2', 'meta+2'], () => {
    const zoom = graph.zoom()
    if (zoom > 0.5) {
      graph.zoom(-0.1)
    }
  })

  // save
  graph.bindKey(['meta+s', 'ctrl+s'], () => {
    saveCurrentDrawing()
    return false
  })

  // 添加快捷键导出SVG
  graph.bindKey(['ctrl+e', 'meta+e'], () => {
    // 获取画布中所有节点和边
    const allNodes = graph.getNodes()
    const allEdges = graph.getEdges()
    const allCells = [...allNodes, ...allEdges]

    // 检查画布是否为空，如果为空则提示无法导出
    if (allCells.length === 0) {
      ElMessage.warning('画布为空，无法导出SVG图片')
      return false
    }

    exportSelectedNodesAsSVG()
    return false
  })

  // 控制连接桩显示/隐藏
  const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
    for (let i = 0, len = ports.length; i < len; i += 1) {
      ports[i].style.visibility = show ? 'visible' : 'hidden'
    }
  }
  graph.on('node:mouseenter', ({ node }) => {
    // 检查是否为模块节点
    const drawingModules = modules.value.get(activeDrawingId.value)
    if (drawingModules && drawingModules.has(node.id)) {
      // 模块节点：只有当模块有端口时才显示连接桩
      const moduleData = drawingModules.get(node.id)
      if (moduleData && moduleData.portCount > 0) {
        // 显示模块的连接桩
        const nodeView = node.findView(graph)
        if (nodeView) {
          const ports = nodeView.container.querySelectorAll('.x6-port-body') as NodeListOf<SVGElement>
          showPorts(ports, true)
        }
      }
      return
    }

    // 检查是否为端口连接器节点或选择组节点
    const nodeData = node.getData()
    if (nodeData?.isPortConnector || node.shape === 'selection-group') {
      // 特殊节点不显示额外的连接桩
      return
    }

    // 只查询和显示当前节点的连接桩
    const nodeView = node.findView(graph)
    if (nodeView) {
      const ports = nodeView.container.querySelectorAll('.x6-port-body') as NodeListOf<SVGElement>
      showPorts(ports, true)
    }
  })
  graph.on('node:mouseleave', ({ node }) => {
    // 隐藏当前节点的连接桩（包括模块节点）
    const nodeView = node.findView(graph)
    if (nodeView) {
      const ports = nodeView.container.querySelectorAll('.x6-port-body') as NodeListOf<SVGElement>
      showPorts(ports, false)
    }
  })
  // 注册自定义节点
  //- 通过 `Graph.registerNode` 注册了不同形状（矩形、圆形、多边形等）的自定义节点，并且定义了连接桩的位置和样式。
  // 端口配置已迁移到nodeProperties.json，此处保留备用
  /*
  const ports = {
    groups: {
      top: {
        position: 'top',
        attrs: {
          circle: {
            r: 6, // 增大半径从4到8
            magnet: true,
            stroke: '#1890FF', // 更明显的蓝色边框
            strokeWidth: 2, // 增加边框宽度
            fill: '#E6F7FF', // 浅蓝色背景
            style: {
              visibility: 'hidden',
              cursor: 'crosshair', // 添加鼠标指针样式
            },
          },
        },
      },
      right: {
        position: 'right',
        attrs: {
          circle: {
            r: 6, // 增大半径从4到8
            magnet: true,
            stroke: '#1890FF', // 更明显的蓝色边框
            strokeWidth: 2, // 增加边框宽度
            fill: '#E6F7FF', // 浅蓝色背景
            style: {
              visibility: 'hidden',
              cursor: 'crosshair', // 添加鼠标指针样式
            },
          },
        },
      },
      bottom: {
        position: 'bottom',
        attrs: {
          circle: {
            r: 6, // 增大半径从4到8
            magnet: true,
            stroke: '#1890FF', // 更明显的蓝色边框
            strokeWidth: 2, // 增加边框宽度
            fill: '#E6F7FF', // 浅蓝色背景
            style: {
              visibility: 'hidden',
              cursor: 'crosshair', // 添加鼠标指针样式
            },
          },
        },
      },
      left: {
        position: 'left',
        attrs: {
          circle: {
            r: 6, // 增大半径从4到8
            magnet: true,
            stroke: '#1890FF', // 更明显的蓝色边框
            strokeWidth: 2, // 增加边框宽度
            fill: '#E6F7FF', // 浅蓝色背景
            style: {
              visibility: 'hidden',
              cursor: 'crosshair', // 添加鼠标指针样式
            },
          },
        },
      },
    },
    items: [{ group: 'top' }, { group: 'right' }, { group: 'bottom' }, { group: 'left' }],
  }
  */

  // 动态注册节点 - 支持多种数据源（JSON文件、远程API等）
  const initializeNodes = async (dataSource?: string | (() => Promise<any>)) => {
    try {
      const nodeInfoModule = await import('./utils/nodeInfo')
      const loadNodeRegistrationsWithCache = nodeInfoModule.loadNodeRegistrationsWithCache
      const registerNodesFromJSON = nodeInfoModule.registerNodesFromJSON

      // 加载节点配置和Stencil组配置（支持缓存）
      const jsonData = await loadNodeRegistrationsWithCache(dataSource, true)
      nodeRegistrationsFromJSON.value = jsonData.nodeRegistrations
      stencilGroupsFromJSON.value = jsonData.stencilGroups

      // console.log('加载的节点配置:', nodeRegistrationsFromJSON.value)
      // console.log('加载的Stencil组配置:', stencilGroupsFromJSON.value)

      // 动态注册所有节点
      await registerNodesFromJSON(Graph, nodeRegistrationsFromJSON.value)
      isNodesLoaded.value = true
      // console.log('节点动态注册成功，共注册了', nodeRegistrationsFromJSON.value.length, '个节点')
    } catch {
      // console.error('加载NodeInfo模块失败:', error)
      // 如果主数据源失败，尝试从本地备份加载
      try {
        // console.log('尝试从本地备份加载节点配置...')
        await initializeNodesFromFallback()
      } catch {
        // console.error('备份数据源也失败:', fallbackError)
      }
    }
  }

  // 备用数据源加载
  const initializeNodesFromFallback = async () => {
    const nodeInfoModule = await import('./utils/nodeInfo')
    const loadNodeRegistrationsFromJSON = nodeInfoModule.loadNodeRegistrationsFromJSON
    const registerNodesFromJSON = nodeInfoModule.registerNodesFromJSON

    const jsonData = await loadNodeRegistrationsFromJSON()
    nodeRegistrationsFromJSON.value = jsonData.nodeRegistrations
    stencilGroupsFromJSON.value = jsonData.stencilGroups
    await registerNodesFromJSON(Graph, nodeRegistrationsFromJSON.value)
    isNodesLoaded.value = true
    // console.log('从备用数据源加载节点配置成功')
  }

  // 初始化节点并加载到Stencil - 支持多种数据源
  const initializeNodesAndStencil = async (dataSource?: string | (() => Promise<any>)) => {
    try {
      // 先注册节点
      await initializeNodes(dataSource)

            // 等待节点注册完成后创建Stencil并加载节点
      setTimeout(() => {
        if (isNodesLoaded.value && nodeRegistrationsFromJSON.value.length > 0) {
          // 先创建Stencil
          const stencilInstance = createStencil()
          if (stencilInstance) {
            // 过滤掉连接桩组相关的节点注册信息
            const filteredGroups = stencilGroupsFromJSON.value.filter((group) => group.title !== '自定义连接桩')
            const filteredNodeRegistrations = nodeRegistrationsFromJSON.value.filter((node) => node.stencilGroup !== 'group6')

            // 然后加载节点到Stencil（排除连接桩节点）
            loadStencilFromJSON(graph, stencilInstance, filteredGroups, filteredNodeRegistrations)
          }
        }
      }, 100)
    } catch (error) {
      console.error('初始化节点和Stencil失败:', error)
    }
  }

  // 根据环境选择数据源
  const getDataSource = () => {
    // 在生产环境中，可以从环境变量或配置中获取API端点
    if (import.meta.env.VITE_USE_API === 'true') {
      // 使用远程API
      const apiEndpoint = import.meta.env.VITE_NODE_CONFIG_API || '/api/node-configurations'
      return apiEndpoint
    } else if (import.meta.env.VITE_USE_CUSTOM_JSON === 'true') {
      // 使用自定义JSON文件
      return import.meta.env.VITE_CUSTOM_JSON_PATH || '/src/views/index/mockData/nodeProperties.json'
    } else {
      // 使用默认JSON文件
      return
    }
  }

  // 初始化系统
  initializeNodesAndStencil(getDataSource())

  // 注册右键菜单事件
  graph.on('node:contextmenu', ({ e, cell }) => {
    e.preventDefault()

    // 获取当前所有选中元素
    const selectedCells = graph.getSelectedCells()

    // 如果当前右键的节点不在选中元素中，则清空选择并选中该节点
    if (!selectedCells.includes(cell)) {
      graph.cleanSelection()
      graph.select(cell)
      selectedCells.length = 0 // 清空数组
      selectedCells.push(cell) // 将当前节点加入
    }

    // 储存当前选中的cell
    currentCell.value = cell

    // 根据选中的元素数量决定显示哪种菜单
    if (selectedCells.length >= 2) {
      // 多选时显示多选菜单
      currentMenuOptions.value = multiSelectMenuOptions
    } else {
      // 检查是否为模块节点
      const drawingModules = modules.value.get(activeDrawingId.value)
      if (drawingModules && drawingModules.has(cell.id)) {
        // 如果是模块节点，显示模块菜单，根据是否有图片动态调整
        const nodeData = cell.getData()
        const hasCustomImage = nodeData?.hasCustomImage

        // 创建动态模块菜单选项
        const dynamicModuleMenuOptions = moduleMenuOptions.filter((option) => {
          // 如果节点有图片，隐藏"上传图片"选项
          if (option.value === 'uploadImage' && hasCustomImage) {
            return false
          }
          // 如果节点没有图片，隐藏"移除图片"选项
          if (option.value === 'removeImage' && !hasCustomImage) {
            return false
          }
          return true
        })

        currentMenuOptions.value = dynamicModuleMenuOptions
      } else {
        // 单选时显示普通节点菜单，根据节点是否有图片动态调整
        const nodeData = cell.getData()
        const hasCustomImage = nodeData?.hasCustomImage

        // 创建动态菜单选项
        const dynamicMenuOptions = menuOptions.filter((option) => {
          // 如果节点有图片，隐藏"上传图片"选项
          if (option.value === 'uploadImage' && hasCustomImage) {
            return false
          }
          // 如果节点没有图片，隐藏"移除图片"选项
          if (option.value === 'removeImage' && !hasCustomImage) {
            return false
          }
          return true
        })

        currentMenuOptions.value = dynamicMenuOptions
      }
    }

    // 设置右键菜单位置
    contextMenuPosition.value = { x: e.clientX, y: e.clientY }
    // 显示菜单
    contextMenuVisible.value = true
  })

  // 移动到边上时修改鼠标样式
  graph.on('edge:mouseenter', ({ edge }) => {
    const edgePath = edge.findView(graph)?.findOne('path')
    if (edgePath) {
      edgePath.setAttribute('cursor', 'pointer')
    }

    // 如果边已被选中，不需要额外处理
    if (edge.hasTools()) {
      // 边已经选中，保持当前状态
    }
  })

  graph.on('edge:mouseleave', ({ edge }) => {
    const edgePath = edge.findView(graph)?.findOne('path')
    if (edgePath) {
      edgePath.setAttribute('cursor', 'default')
    }

    // 移除空心箭头
  })

  // 添加边的右键菜单事件
  graph.on('edge:contextmenu', ({ e, cell }) => {
    e.preventDefault()

    // 获取当前所有选中元素
    const selectedCells = graph.getSelectedCells()

    // 如果当前右键的边不在选中元素中，则清空选择并选中该边
    if (!selectedCells.includes(cell)) {
      graph.cleanSelection()
      graph.select(cell)
      selectedCells.length = 0 // 清空数组
      selectedCells.push(cell) // 将当前边加入
    }

    // 储存当前选中的cell
    currentCell.value = cell

    // 根据选中的元素数量决定显示哪种菜单
    if (selectedCells.length >= 2) {
      // 多选时显示多选菜单
      currentMenuOptions.value = multiSelectMenuOptions
    } else {
      // 单选边时显示边菜单
      currentMenuOptions.value = edgeMenuOptions
    }

    // 设置右键菜单位置
    contextMenuPosition.value = { x: e.clientX, y: e.clientY }
    // 显示菜单
    contextMenuVisible.value = true
  })

  // 画布空白处点击时关闭右键菜单
  graph.on('blank:click', () => {
    closeContextMenu()

    // 重置节点选中状态
    isNodeSelected.value = false
    selectedNode.value = null

    graph.cleanSelection()

    // 如果当前标签页是参数或格式，切换回图纸选项
    if (activeTab.value === '参数' || activeTab.value === '格式') {
      activeTab.value = '图纸选项'
    }
  })

  // 单元格点击时关闭右键菜单
  graph.on('cell:click', () => {
    closeContextMenu()
  })

  // 使用X6内置的鼠标事件处理，不需要额外监听

  // 添加边点击事件
  graph.on('edge:click', ({ edge }) => {
    // 确保点击边时选中该边
    graph.cleanSelection()
    graph.select(edge)
  })

  // 使用X6内置的鼠标事件处理，不需要额外设置

  // 设置初始状态
  if (!referenceStandardsVisible.value) {
    graph.disablePanning()
  }

  // 添加边选择框和样式
  const style = document.createElement('style')
  style.textContent = `
    /* 确保画布默认显示普通鼠标指针 */
    #graph-container {
      cursor: default !important;
    }

    /* 只有在按下Ctrl键时才显示手形指针，通过JS动态添加类实现 */
    #graph-container.panning-mode {
      cursor: grab !important;
    }

    #graph-container.panning-mode:active {
      cursor: grabbing !important;
    }

    /* 边的选中样式 */
    .x6-edge.x6-edge-selected path {
      stroke: #000000 !important; // 选中时保持黑色
      stroke-width: 2px !important; // 选中时保持与节点一致的粗细
    }

    /* 边的选择框样式 */
    .x6-edge.x6-edge-selected .x6-edge-selection-box {
      stroke: #1890FF;
      stroke-dasharray: 5;
      stroke-width: 1px;
      fill: none;
      rx: 0;
      ry: 0;
    }

    /* 为选择框增加内边距 */
    /* 注释掉这个规则，让Transform框能正常显示 */
    /* .x6-widget-selection-box {
      display: none;
    } */

    /* 调整边的选择框样式以增加与边的间距 */
    .x6-edge-selected .x6-edge-selection-box rect {
      stroke: #1890FF;
      stroke-dasharray: 5;
      fill: none;
      rx: 0;
      ry: 0;
    }

    /* 选择手柄样式 */
    .x6-edge-selected .x6-edge-tool-remove circle {
      fill: white;
      stroke: #1890FF;
      stroke-width: 1;
    }

    .x6-edge-selected .x6-edge-tool-remove path {
      stroke: #1890FF;
      fill: none;
      stroke-width: 1;
    }
  `
  document.head.appendChild(style)

  // 监听节点位置变化事件
  graph.on('cell:change:position', ({ cell }) => {
    if (cell.isNode() && selectedNode.value && cell.id === selectedNode.value.id) {
      const position = cell.getPosition()
      nodeX.value = position.x
      nodeY.value = position.y
    }
  })

  // 监听节点transform变化事件（处理拖拽变形工具的缩放）
  graph.on('node:change:attrs', ({ node }) => {
    if (node.isNode()) {
      const nodeData = node.getData()
      if (nodeData?.hasCustomImage) {
        // 获取当前节点尺寸并更新图片
        const size = node.getSize()
        updateNodeImageSize(node, size)
      }
    }
  })

  // 监听节点大小变化事件
  graph.on('cell:change:size', ({ cell }) => {
    if (cell.isNode()) {
      const size = cell.getSize()

      // 如果是当前选中的节点，更新尺寸状态
      if (selectedNode.value && cell.id === selectedNode.value.id) {
        nodeWidth.value = size.width
        nodeHeight.value = size.height
      }

      // 如果节点有自定义图片，同步更新图片尺寸
      const nodeData = cell.getData()
      if (nodeData?.hasCustomImage) {
        updateNodeImageSize(cell as Node, size)
      }
    }
  })

  // 选中边时添加工具和箭头
  graph.on('edge:selected', ({ edge }) => {
    // 更新边选择状态
    selectedEdge.value = edge
    isEdgeSelected.value = true
    selectedNode.value = null
    isNodeSelected.value = false
    isMultipleNodesSelected.value = false

    // 切换到格式选项卡
    activeTab.value = '格式'

    // 更新边的属性值
    updateEdgeProperties(edge)

    // 添加箭头标记
    // edge.attr('line/targetMarker', {
    //   name: 'block',
    //   width: 8,
    //   height: 8,
    //   attrs: {
    //     stroke: '#000000',
    //     strokeWidth: 2,
    //     fill: '#000000',
    //   },
    // })

    edge.addTools([
      'boundary', // 添加边界框
      {
        name: 'vertices', // 添加顶点工具，用于显示和编辑边的顶点
        args: {
          padding: 6, // 顶点周围的空白区域
          attrs: {
            fill: '#1890FF',
            stroke: '#FFFFFF',
            'stroke-width': 1,
            cursor: 'move',
          },
        },
      },
      {
        name: 'segments', // 添加分段工具
        args: {
          padding: 6,
          attrs: {
            fill: '#1890FF',
            stroke: '#FFFFFF',
            'stroke-width': 1,
            cursor: 'crosshair',
          },
        },
      },
      {
        name: 'source-arrowhead', // 源端拖拽工具
        args: {
          attrs: {
            fill: '#1890FF',
            stroke: '#FFFFFF',
            'stroke-width': 1,
            cursor: 'move',
          },
        },
      },
      {
        name: 'target-arrowhead', // 目标端拖拽工具
        args: {
          attrs: {
            fill: '#1890FF',
            stroke: '#FFFFFF',
            'stroke-width': 1,
            cursor: 'move',
          },
        },
      },
    ])
  })

  // 取消选中边时移除工具和箭头
  graph.on('edge:unselected', ({ edge }) => {
    // 重置边选择状态
    selectedEdge.value = null
    isEdgeSelected.value = false

    // 如果当前是格式选项卡且没有选中节点，切换回图纸选项
    if (activeTab.value === '格式' && !isNodeSelected.value) {
      activeTab.value = '图纸选项'
    }

    // 检查边是否连接到节点
    const target = edge.getTarget()

    if (!target || (typeof target === 'object' && !('cell' in target))) {
      // 未连接时保持显示X标记
      edge.attr('line/targetMarker', {
        name: 'cross',
        size: 8,
        offset: 1, // X标记向内偏移，确保在边的末端
        attrs: {
          stroke: '#ff0000',
          strokeWidth: 2,
          fill: 'none',
        },
      })
    } else {
      // 连接到节点时移除箭头标记，只显示线条
      edge.attr('line/targetMarker', null)
    }

    edge.removeTools()
  })

  // 监听画布缩放事件，确保边能够跟随缩放
  graph.on('scale', ({ sx, sy }) => {
    // 无需手动调整边的线宽，让边自然跟随缩放
    const edges = graph.getEdges()
    edges.forEach(edge => {
      // 确保边的样式保持一致，不需要手动调整strokeWidth
      edge.attr('line/strokeWidth', 2)
    })
  })
  // 边连接成功后的处理
  graph.on('edge:connected', ({ edge }) => {
    // 连接成功后，如果边已被选中则显示箭头，否则不显示
     const selectedCells = graph.getSelectedCells()
     if (selectedCells.includes(edge)) {
       edge.attr('line/targetMarker', {
         name: 'block',
         width: 8,
         height: 8,
        attrs: {
           stroke: '#000000',
           strokeWidth: 2,
           fill: '#000000',
         },
       })
     } else {
       // 未选中时移除箭头标记
       edge.attr('line/targetMarker', null)
     }

    // 保存画布状态
    saveGraphContent()
  })

  // 边移动事件处理（拖拽过程中）
  graph.on('edge:mousemove', ({ edge }) => {
    const target = edge.getTarget()
    const selectedCells = graph.getSelectedCells()
    const isEdgeSelected = selectedCells.includes(edge)

    // 检查目标端是否连接到节点
    if (!target || (typeof target === 'object' && !('cell' in target))) {
      // 未连接时显示X标记
      edge.attr('line/targetMarker', {
        name: 'cross',
        size: 8,
        offset: 1, // X标记向内偏移，确保在边的末端
        attrs: {
          stroke: '#ff0000',
          strokeWidth: 2,
          fill: 'none',
        },
      })
    } else {
      // 连接到节点时，只有选中状态才显示箭头
      // if (isEdgeSelected) {
      //   edge.attr('line/targetMarker', {
      //     name: 'block',
      //     width: 8,
      //     height: 8,
      //     offset: 0, // 箭头正常位置
      //     attrs: {
      //       stroke: '#000000',
      //       strokeWidth: 2,
      //       fill: '#000000',
      //     },
      //   })
      // } else {
      //   // 未选中时移除箭头
      //   edge.attr('line/targetMarker', null)
      // }
    }
  })

  // 确保初始状态下所有边都不显示箭头
  removeAllEdgeArrows()

  // 节点添加事件，初始化SVG文本
  graph.on('cell:added', ({ cell }) => {
    if (cell.isNode()) {
      const node = cell as Node

      // 如果节点有data.label且当前文本为空，恢复文本
      const nodeData = node.getData() || {}
      const label = nodeData.label || node.attr('label/text') || node.attr('text/text')

      if (label) {
        // 确保标签文本正确显示，设置为text属性（不受elementsStandard影响）
        node.attr('text/text', label)
        node.attr('text/fill', '#262626')
        node.attr('text/fontSize', 12)
                node.attr('text/fontFamily', 'Arial')
        node.attr('text/textAnchor', 'middle')
        node.attr('text/textVerticalAnchor', 'middle')
      }

      // 延迟初始化，确保节点已完全渲染
      setTimeout(() => {
        initializeNodeSVGText(node)
        // 只有当elementsStandard为true时才应用标签设置
        if (elementsStandard.value) {
          applyLabelSettingToNode(node)
        }
      }, 100)

      // 触发连接桩选项更新
      nodesUpdateTrigger.value++
    }
  })

  // 节点删除事件，更新连接桩选项
  graph.on('cell:removed', ({ cell }) => {
    if (cell.isNode()) {
      // 触发连接桩选项更新
      nodesUpdateTrigger.value++
    }
  })

  // 边添加事件，检查是否为悬空边
  graph.on('edge:added', ({ edge }) => {
    const target = edge.getTarget()

    // 如果目标端未连接到节点，显示X标记
    if (!target || (typeof target === 'object' && !('cell' in target))) {
      edge.attr('line/targetMarker', {
        name: 'cross',
        size: 8,
        offset: 1, // X标记向内偏移，确保在边的末端
        attrs: {
          stroke: '#ff0000',
          strokeWidth: 2,
          fill: 'none',
        },
      })
    } else {
      // 连接到节点的边默认不显示箭头，只有选中时才显示
      edge.attr('line/targetMarker', null)
    }
  })

  // 设置键盘事件监听
  globalThis.addEventListener('keydown', handleKeyDown)
  globalThis.addEventListener('keyup', handleKeyUp)

  // 设置基本事件处理
  setupBasicEvents()

  // 多选节点的右键菜单
  graph.on('blank:contextmenu', ({ e }) => {
    e.preventDefault()
    const selectedCells = graph.getSelectedCells()
    if (selectedCells.length >= 2) {
      // 显示多选菜单
      currentMenuOptions.value = multiSelectMenuOptions
    } else {
      // 显示画布菜单
      currentMenuOptions.value = canvasMenuOptions
    }
    // 设置右键菜单位置
    contextMenuPosition.value = { x: e.clientX, y: e.clientY }
    // 显示菜单
    contextMenuVisible.value = true
  })

  // 添加节点点击事件处理，实现多选状态下点击单个节点只选中该节点
  graph.on('node:click', ({ node, e }) => {
    // 获取当前选中的节点
    const selectedCells = graph.getSelectedCells()
    const selectedNodes = selectedCells.filter((cell) => cell.isNode())

    // 如果当前有多个节点被选中，且没有按住修饰键
    if (selectedNodes.length > 1 && !e.ctrlKey && !e.metaKey) {
      // 检查点击的节点是否在当前选中的节点中
      const isClickedNodeSelected = selectedNodes.some((selectedNode) => selectedNode.id === node.id)

      if (isClickedNodeSelected) {
        // 如果点击的是已选中的节点，则只选中这个节点（单选）
        graph.cleanSelection()
        graph.select(node)
      }
      // 如果点击的是未选中的节点，X6会自动处理（清除选择并选中新节点）
    }
    // 其他情况保持X6的默认行为
  })

  // 监听选择变化事件，处理多选情况
  graph.on('selection:changed', () => {
    const selectedCells = graph.getSelectedCells()
    const selectedNodes = selectedCells.filter((cell) => cell.isNode())
    const selectedEdges = selectedCells.filter((cell) => cell.isEdge())

    // 更新多选状态
    isMultipleNodesSelected.value = selectedNodes.length > 1

    // 获取图表容器元素
    const graphContainer = document.getElementById('graph-container')

    // 使用requestAnimationFrame优化Transform控制，减少延迟
    requestAnimationFrame(() => {
      // 清除所有Transform框
      graph.clearTransformWidgets()

      if (selectedNodes.length === 1) {
        // 单个节点选中时，只显示Transform框，隐藏Selection框
        const node = selectedNodes[0] as Node
        graph.createTransformWidget(node)

        // 添加单选CSS类
        if (graphContainer) {
          graphContainer.classList.add('single-node-selected')
          graphContainer.classList.remove('multiple-nodes-selected')
        }
      } else if (selectedNodes.length > 1) {
        // 多个节点选中时，显示Selection框，不显示Transform框
        // 添加多选CSS类
        if (graphContainer) {
          graphContainer.classList.add('multiple-nodes-selected')
          graphContainer.classList.remove('single-node-selected')
        }
      } else {
        // 无选中时，清除所有CSS类
        if (graphContainer) {
          graphContainer.classList.remove('single-node-selected', 'multiple-nodes-selected')
        }
      }
    })

    // 如果是多选状态且当前是参数或格式标签，切换到图纸选项
    if (isMultipleNodesSelected.value && (activeTab.value === '参数' || activeTab.value === '格式')) {
      activeTab.value = '图纸选项'
    }

    // 处理边选择
    if (selectedEdges.length === 1 && selectedNodes.length === 0) {
      // 单个边被选中且没有选中节点
      const edge = selectedEdges[0]
      selectedEdge.value = edge
      isEdgeSelected.value = true
      selectedNode.value = null
      isNodeSelected.value = false
      // 切换到格式标签页，边直接显示格式面板
      activeTab.value = '格式'
      updateEdgeProperties(edge)
    } else if (selectedEdges.length === 0) {
      // 没有选中边
      selectedEdge.value = null
      isEdgeSelected.value = false
    }

    // 如果没有选中节点，清除配置并切换到图纸选项
    if (selectedNodes.length === 0 && selectedEdges.length === 0) {
      isNodeSelected.value = false
      selectedNode.value = null
      isEdgeSelected.value = false
      selectedEdge.value = null
      currentNodeConfiguration.value = null
      nodePropertiesData.value = {}

      // 取消选中时，切换到图纸选项
      if (activeTab.value === '参数' || activeTab.value === '格式') {
        activeTab.value = '图纸选项'
      }
    } else if (selectedNodes.length === 1 && selectedEdges.length === 0) {
      // 单个节点被选中
      const node = selectedNodes[0]

      // 重置边选择状态
      selectedEdge.value = null
      isEdgeSelected.value = false

      // 确保节点状态正确更新
      if (selectedNode.value?.id !== node.id) {
        console.log('检测到节点切换，更新配置:', { from: selectedNode.value?.id, to: node.id })

        // 立即更新选中节点状态
        selectedNode.value = node as Node
        isNodeSelected.value = true

        // 立即更新节点配置
        nextTick(() => {
          updateNodeConfiguration(node as Node)
        })
      }

      // 如果选中的是选择组，确保切换到选择组标签
      if (node.shape === 'selection-group' && activeTab.value !== '选择组') {
        activeTab.value = '选择组'
      } else if (node.shape !== 'selection-group') {
        // 如果不是选择组，切换到参数选项卡
        activeTab.value = '参数'
      }
    }
  })

  // 处理节点选择事件
  graph.on('node:selected', ({ node }) => {
    // console.log('节点选择事件触发:', node.id, node.shape)

    // 首先清除之前的状态，确保界面更新
    currentNodeConfiguration.value = null
    nodePropertiesData.value = {}

    // 更新选中节点状态
    selectedNode.value = node
    isNodeSelected.value = true
    isMultipleNodesSelected.value = false

    // 更新节点属性
    const position = node.getPosition()
    const size = node.getSize()
    nodeX.value = position.x
    nodeY.value = position.y
    nodeWidth.value = size.width
    nodeHeight.value = size.height

    // 更新格式属性 - 提取节点的所有样式属性到右侧面板
    nodeBorderWidth.value = node.attr('body/strokeWidth') || 1
    nodeFontSize.value = node.attr('label/fontSize') || node.attr('text/fontSize') || 12
    nodeFontFamily.value = node.attr('label/fontFamily') || node.attr('text/fontFamily') || 'Arial'

    // 提取并更新颜色属性到响应式变量
    nodeFillColor.value = node.attr('body/fill') || '#EFF4FF'
    nodeStrokeColor.value = node.attr('body/stroke') || '#5F95FF'
    nodeLabelColor.value = node.attr('label/fill') || node.attr('text/fill') || '#262626'

    // 更新到组件实例的data中以便右侧面板访问
    if (node.data) {
      node.data = {
        ...node.data,
        formatStyles: {
          fillColor: nodeFillColor.value,
          strokeColor: nodeStrokeColor.value,
          strokeWidth: nodeBorderWidth.value,
          labelColor: nodeLabelColor.value,
          fontSize: nodeFontSize.value,
          fontFamily: nodeFontFamily.value
        }
      }
    }

    // 检查节点是否为选择组
    if (node.shape === 'selection-group') {
      // 如果是选择组，切换到选择组标签
      activeTab.value = '选择组'

      const drawingGroups = selectionGroups.value.get(activeDrawingId.value)
      if (drawingGroups) {
        // 检查该节点是否为选择组
        for (const [groupId /*_*/] of drawingGroups.entries()) {
          if (groupId === node.id) {
            // 找到了选择组，仅选中它，不进入编辑模式
            selectGroupOnly(groupId)
            break
          }
        }
      }
    } else {
      // 如果不是选择组，切换到参数选项卡
      activeTab.value = '参数'
    }

    // 检查节点是否为选择组（现有逻辑，保留但移除重复处理）
    const drawingGroups = selectionGroups.value.get(activeDrawingId.value)
    if (drawingGroups && node.shape !== 'selection-group') {
      // 检查该节点是否为选择组
      for (const [groupId] of drawingGroups.entries()) {
        if (groupId === node.id) {
          // 找到了选择组，仅选中它，不进入编辑模式
          selectGroupOnly(groupId)
          break
        }
      }
    }

    // 使用 nextTick 确保在 DOM 更新后再更新节点配置
    nextTick(() => {
      updateNodeConfiguration(node)
      // console.log('节点配置已更新:', {
      //   nodeId: node.id,
      //   nodeName: currentNodeConfiguration.value?.name,
      //   nodeData: nodePropertiesData.value,
      // })
    })
  })

  // 处理节点取消选择事件
  graph.on('node:unselected', () => {
    // 使用selection:changed事件来处理节点选择状态的更新
  })

  // 添加选择组双击处理
  graph.on('node:dblclick', ({ node }) => {
    // 检查节点是否为选择组
    const drawingGroups = selectionGroups.value.get(activeDrawingId.value)
    if (drawingGroups) {
      // 检查该节点是否为选择组
      for (const [groupId] of drawingGroups.entries()) {
        if (groupId === node.id) {
          // 是选择组，进入编辑模式
          editGroup(groupId)
          return // 防止触发其他双击处理
        }
      }
    }

    // 检查是否为模块节点（现有代码）
    const drawingModulesMap = modules.value.get(activeDrawingId.value)
    if (drawingModulesMap && drawingModulesMap.has(node.id)) {
      // 是模块节点，打开模块
      openModule(node.id)
    }
  })

  // 自定义选择组标识类型
  const registerSelectionGroup = () => {
    // 为选择组添加交互增强
    Graph.registerNode(
      'selection-group',
      {
        inherit: 'rect',
        attrs: {
          body: {
            fill: '#E8F4FF',
            stroke: '#5F95FF',
            strokeWidth: 1.5,
            strokeDasharray: '5,5',
            opacity: 0.25,
            rx: 8,
            ry: 8,
          },
          label: {
            fill: '#333333',
            fontSize: 14,
            fontWeight: 'bold',
            refX: 10,
            refY: 8,
            textAnchor: 'start',
            textVerticalAnchor: 'top',
          },
        },
        zIndex: -1,
      },
      true
    )
  }

  // 自定义模块节点类型
  const registerModuleNode = () => {
    // 为模块添加交互增强
    Graph.registerNode(
      'module-node',
      {
        inherit: 'rect',
        attrs: {
          body: {
            fill: '#FFFFFF',
            stroke: '#5F95FF',
            strokeWidth: 2,
            rx: 5,
            ry: 5,
          },
          label: {
            fill: '#333333',
            fontSize: 14,
            fontWeight: 'bold',
            refX: 0.5,
            refY: 0.5,
            textAnchor: 'middle',
            textVerticalAnchor: 'middle',
          },
        },
        // 模块节点默认不显示任何端口
        ports: {
          groups: {},
          items: [],
        },
        zIndex: 1,
      },
      true
    )
  }

  // 自定义端口连接器节点类型
  const registerPortConnectorNode = () => {
    Graph.registerNode(
      'port-connector',
      {
        inherit: 'ellipse',
        width: 30,
        height: 30,
        attrs: {
          body: {
            strokeWidth: 2,
            stroke: '#0066CC',
            fill: '#1890FF',
            rx: 15,
            ry: 15,
          },
          label: {
            fontSize: 12,
            fill: '#fff',
            textAnchor: 'middle',
            textVerticalAnchor: 'middle',
          },
        },
        ports: {
          groups: {
            center: {
              position: 'ellipse',
              attrs: {
                circle: {
                  r: 4,
                  magnet: true,
                  stroke: '#fff',
                  strokeWidth: 2,
                  fill: '#1890FF',
                },
              },
            },
          },
          items: [{ group: 'center' }],
        },
        zIndex: 2,
      },
      true
    )
  }

  // 注册选择组节点类型
  registerSelectionGroup()
  // 注册模块节点类型
  registerModuleNode()
  // 注册端口连接器节点类型
  registerPortConnectorNode()

  // 添加选择组拖拽移动功能
  let isMovingGroup = false
  let groupMoveStartPositions = new Map()
  let groupStartPosition: { x: number; y: number } | null = null

  // 监听选择组开始移动
  graph.on('node:move', ({ node }) => {
    if (node.shape === 'selection-group') {
      isMovingGroup = true

      // 记录选择组的起始位置
      groupStartPosition = node.getPosition()

      // 获取选择组数据
      const drawingGroups = selectionGroups.value.get(activeDrawingId.value)
      if (drawingGroups) {
        const groupData = drawingGroups.get(node.id)
        if (groupData && groupData.members) {
          // 记录组内成员的起始位置
          groupMoveStartPositions.clear()
          for (const memberId of groupData.members) {
            const memberCell = graph.getCellById(memberId)
            if (memberCell && memberCell.isNode()) {
              groupMoveStartPositions.set(memberId, memberCell.getPosition())
            }
          }
        }
      }
    }
  })

  // 监听选择组移动中
  graph.on('node:moving', ({ node }) => {
    if (node.shape === 'selection-group' && isMovingGroup && groupStartPosition) {
      // 获取选择组数据
      const drawingGroups = selectionGroups.value.get(activeDrawingId.value)
      if (drawingGroups) {
        const groupData = drawingGroups.get(node.id)
        if (groupData && groupData.members) {
          // 计算选择组的移动偏移量
          const currentPos = node.getPosition()
          const deltaX = currentPos.x - groupStartPosition.x
          const deltaY = currentPos.y - groupStartPosition.y

          // 移动组内成员
          for (const memberId of groupData.members) {
            const memberCell = graph.getCellById(memberId)
            const startPos = groupMoveStartPositions.get(memberId)
            if (memberCell && memberCell.isNode() && startPos) {
              // 计算新位置
              const newPos = {
                x: startPos.x + deltaX,
                y: startPos.y + deltaY,
              }
              memberCell.setPosition(newPos.x, newPos.y)
            }
          }
        }
      }
    }
  })

  // 监听选择组移动结束
  graph.on('node:moved', ({ node }) => {
    if (node.shape === 'selection-group' && isMovingGroup) {
      isMovingGroup = false
      groupMoveStartPositions.clear()
      groupStartPosition = null

      // 保存图纸内容
      saveGraphContent()
    }
  })

  // group selection
  graph.bindKey(['meta+g', 'ctrl+g'], () => {
    const selectedCells = graph.getSelectedCells()
    if (selectedCells.length >= 2) {
      createSelectionGroup()
    }
    return false
  })

  // 加载更新的模块数据
  loadUpdatedModules()

  // 清理可能的重复模块节点
  cleanupDuplicateModules()

  // 注意：checkStorageUsage 和 cleanupModuleStorage 函数在文件后面定义
  // 这些调用会在函数定义后执行

  // 注册节点双击事件处理器
  graph.on('node:dblclick', ({ node }) => {
    // 获取当前图纸的模块Map
    const drawingModulesMap = modules.value.get(activeDrawingId.value)
    if (!drawingModulesMap) return

    // 检查该节点是否为模块
    if (drawingModulesMap.has(node.id)) {
      // 是模块节点，打开模块
      openModule(node.id)
    }
  })

  // 使用相对定位后，端口位置会自动随节点变换调整，不需要手动处理

  // 使用相对定位后，不再需要手动处理端口位置更新

  // 页面初始化完成后，恢复节点配置（包括模块节点）
  setTimeout(() => {
    restoreNodeConfigurations()
  }, 500)
})

// 组件卸载时清理事件监听器
onUnmounted(() => {
  // 清理键盘事件监听
  globalThis.removeEventListener('keydown', handleKeyDown)
  globalThis.removeEventListener('keyup', handleKeyUp)

  // 清理右键菜单事件监听
  document.removeEventListener('contextmenu', handleDocumentContextMenu)

  // 清理图形容器的右键菜单事件和鼠标事件
  const graphContainer = document.getElementById('graph-container')
  if (graphContainer) {
    graphContainer.removeEventListener('contextmenu', handleGraphContextMenu)
    graphContainer.removeEventListener('mousedown', handleMouseDown)
    graphContainer.removeEventListener('mouseup', handleMouseUp)
  }

  // 清理图片更新定时器
  imageUpdateTimeouts.forEach((timeout) => {
    clearTimeout(timeout)
  })
  imageUpdateTimeouts.clear()

  // 清理graph实例
  if (graphRef.value) {
    graphRef.value.dispose()
  }
})

// 显示模块创建对话框
const showModuleDialog = () => {
  if (!graphRef.value) return

  const selectedCells = graphRef.value.getSelectedCells()
  if (selectedCells.length < 2) {
    ElMessage.warning('创建模块至少需要选择两个元素')
    return
  }

  // 重置表单
  moduleFormData.value = {
    resourceId: `a${Math.floor(Math.random() * 100000000)}`,
    modelId: moduleFormData.value.modelId || `a5${Math.floor(Math.random() * 10000000)}`,
    projectId: 'my-project',
    name: '',
    permission: 'private',
    type: '元件',
    category: '',
    description: '',
  }

  moduleDialogTitle.value = '创建模块'
  isCreatingModule.value = true
  moduleDialogVisible.value = true
}

/**
 * 创建模块
 */
const createModule = () => {
  if (!graphRef.value) return

  const selectedCells = graphRef.value.getSelectedCells()
  if (selectedCells.length < 2) {
    ElMessage.warning('创建模块至少需要选择两个元素')
    return
  }

  // 使用表单验证
  moduleFormRef.value.validate((valid: boolean) => {
    if (!valid) {
      return
    }

    // 创建唯一ID
    const moduleId = `module-${Date.now()}`

    if (!graphRef.value) return

    // 计算包围盒
    const bbox = graphRef.value.getCellsBBox(selectedCells)
    if (!bbox) return

    // 创建模块节点 - 不添加任何端口
    const moduleNode = graphRef.value.addNode({
      id: moduleId,
      shape: 'module-node',
      x: bbox.x,
      y: bbox.y,
      width: bbox.width,
      height: bbox.height,
      attrs: {
        label: {
          text: moduleFormData.value.name || '模块',
          // 确保标签始终可见
          style: {
            visibility: 'visible',
            display: 'block',
            opacity: '1',
          },
        },
      },
      // 初始时不添加任何端口
      ports: {
        groups: {},
        items: [],
      },
      data: {
        moduleId,
        isModule: true,
        portCount: 0, // 记录当前端口数量
      },
    })

    // 存储模块信息
    const moduleData = {
      id: moduleId,
      node: moduleNode,
      name: moduleFormData.value.name || '模块',
      resourceId: moduleFormData.value.resourceId,
      modelId: moduleFormData.value.modelId,
      projectId: moduleFormData.value.projectId,
      permission: moduleFormData.value.permission,
      type: moduleFormData.value.type,
      category: moduleFormData.value.category,
      description: moduleFormData.value.description,
      cells: selectedCells
        .map((cell) => {
          if (graphRef.value) {
            const cellJSON = cell.toJSON()

            // 如果是边，确保完整保存连接信息
            if (cell.isEdge()) {
              const source = cell.getSource()
              const target = cell.getTarget()

              return {
                ...cellJSON,
                source, // 保存完整的source信息，包括端口信息
                target, // 保存完整的target信息，包括端口信息
                attrs: cell.getAttrs(), // 保存完整的样式信息
              }
            }

            // 如果是节点，保存位置和大小信息
            if (cell.isNode()) {
              const position = cell.getPosition()
              const size = cell.getSize()

              return {
                ...cellJSON,
                position,
                size,
                attrs: cell.getAttrs(),
                data: {
                  ...cellJSON.data,
                  position,
                  size,
                },
              }
            }

            return cellJSON
          }
          return null
        })
        .filter(Boolean),
      portCount: 0, // 初始端口数量为0
      // 保存模块节点的尺寸和位置
      moduleSize: moduleNode.getSize(),
      modulePosition: moduleNode.getPosition(),
    }

    // 存储到当前图纸的模块中
    if (!modules.value.has(activeDrawingId.value)) {
      modules.value.set(activeDrawingId.value, new Map())
    }
    const currentModulesMap = modules.value.get(activeDrawingId.value)
    if (currentModulesMap) {
      currentModulesMap.set(moduleId, moduleData)
    }

    // 删除选中的节点（已经包含在模块中了）
    if (graphRef.value) {
      graphRef.value.removeCells(selectedCells)
    }

    // 清除选择状态和隐藏连接桩
    cleanupSelectionAndPorts()

    // 额外的清理，确保所有选择框都被移除
    setTimeout(() => {
      cleanupSelectionAndPorts()
      // 强制重绘以确保UI更新
      if (graphRef.value) {
        graphRef.value.cleanSelection()
        graphRef.value.trigger('blank:click')

        // 确保模块标签可见
        moduleNode.attr('label/style/visibility', 'visible')
        moduleNode.attr('label/style/display', 'block')
        moduleNode.attr('label/style/opacity', '1')
      }
    }, 150)

    // 关闭对话框
    moduleDialogVisible.value = false

    // 显示成功消息
    ElMessage.success(`模块 "${moduleFormData.value.name}" 创建成功`)

    // 保存图纸内容
    saveGraphContent()
  })
}

// 安全地处理模块数据以便存储
const sanitizeModuleDataForStorage = (moduleData: any) => {
  try {
    // 创建一个干净的数据对象，只包含可序列化的必要信息
    const sanitized = {
      id: moduleData.id,
      name: moduleData.name,
      resourceId: moduleData.resourceId,
      modelId: moduleData.modelId,
      projectId: moduleData.projectId,
      permission: moduleData.permission,
      type: moduleData.type,
      category: moduleData.category,
      description: moduleData.description,
      cells: sanitizeCellsData(moduleData.cells),
      portCount: Number(moduleData.portCount) || 0,
      // 图片相关信息：只存储是否有图片的标识，不存储实际图片数据
      hasCustomImage: Boolean(moduleData.hasCustomImage),
      // 如果图片URL是base64，不存储到localStorage，改为存储标识
      imageUrl: isBase64Image(moduleData.imageUrl) ? 'HAS_CUSTOM_IMAGE' : moduleData.imageUrl,
    }

    // 测试序列化大小，如果太大则进一步简化
    const serializedSize = JSON.stringify(sanitized).length
    if (serializedSize > 100000) {
      // 100KB限制
      console.warn('模块数据过大，进行简化处理')
      return createCompactModuleData(moduleData)
    }

    return sanitized
  } catch (error) {
    console.warn('数据处理失败，使用最基本结构:', error)
    return createCompactModuleData(moduleData)
  }
}

// 检查是否为base64图片
const isBase64Image = (url: any): boolean => {
  return typeof url === 'string' && url.startsWith('data:image/')
}

// 清理cells数据，移除大型数据
const sanitizeCellsData = (cells: any[]): any[] => {
  if (!Array.isArray(cells)) return []

  return cells.map((cell) => {
    const cleanCell = { ...cell }

    // 如果cell包含图片数据，进行处理
    if (cleanCell.attrs && cleanCell.attrs.coverImage) {
      const imageUrl = cleanCell.attrs.coverImage.href
      if (isBase64Image(imageUrl)) {
        // 不存储base64图片数据，只保留图片存在的标识
        cleanCell.attrs.coverImage = {
          href: 'HAS_CUSTOM_IMAGE',
          width: cleanCell.attrs.coverImage.width,
          height: cleanCell.attrs.coverImage.height,
          preserveAspectRatio: 'xMidYMid meet',
        }
      }
    }

    return cleanCell
  })
}

// 创建紧凑的模块数据
const createCompactModuleData = (moduleData: any) => {
  return {
    id: moduleData.id || 'unknown',
    name: moduleData.name || '未命名模块',
    cells: [], // 不存储cells数据，详情页面将显示空白画布
    portCount: 0,
    hasCustomImage: Boolean(moduleData.hasCustomImage),
    imageUrl: undefined, // 不存储图片数据
  }
}

// 打开模块
const openModule = (moduleId: string) => {
  if (!graphRef.value) {
    // console.error('图形实例不存在')
    return
  }

  // console.log('打开模块:', { moduleId, activeDrawingId: activeDrawingId.value })

  // 获取当前图纸的模块
  const drawingModules = modules.value.get(activeDrawingId.value)
  if (!drawingModules) {
    // console.error('当前图纸没有模块数据')
    ElMessage.error('当前图纸没有模块数据')
    return
  }

  const moduleData = drawingModules.get(moduleId)
  if (!moduleData) {
    // console.error('找不到指定的模块数据:', moduleId)
    ElMessage.error('找不到指定的模块数据')
    return
  }

  // console.log('准备传递的模块数据:', {
  //   name: moduleData.name,
  //   id: moduleData.id,
  //   cellsCount: moduleData.cells?.length || 0,
  //   portCount: moduleData.portCount || 0,
  // })

  // 设置当前模块ID和活动模块
  currentModuleId.value = moduleId
  activeModule.value = moduleData

  // 从localStorage获取现有数据
  const modulesStr = localStorage.getItem('x6-modules') || '{}'
  let modulesData = JSON.parse(modulesStr)

  // 确保数据结构存在
  if (!modulesData[activeDrawingId.value]) {
    modulesData[activeDrawingId.value] = {}
  }

  // 创建要传递的模块数据副本，确保数据完整性
  const moduleDataCopy = {
    ...moduleData,
    // 确保关键字段存在
    id: moduleId,
    drawingId: activeDrawingId.value,
    portCount: moduleData.portCount || 0,
    // 添加版本控制字段
    version: (moduleData.version || 0) + 1,
    lastModified: new Date().toISOString(),
    // 保存原始位置和大小信息
    originalPosition: moduleData.node ? moduleData.node.getPosition() : null,
    originalSize: moduleData.node ? moduleData.node.getSize() : null,
  }

  // 处理cells数据，确保每个节点的数据完整性
  moduleDataCopy.cells = (moduleData.cells || []).map(
    (cell: {
      shape?: string
      id?: string
      position?: { x: number; y: number }
      size?: { width: number; height: number }
      attrs?: Record<string, any>
      data?: Record<string, any>
    }) => {
      if (cell.shape) {
        // 如果是节点
        const node = graphRef.value?.getCellById(cell.id || '')
        if (node?.isNode()) {
          // 保存节点的完整信息
          return {
            ...cell,
            position: node.getPosition() || cell.position,
            size: node.getSize() || cell.size || { width: 120, height: 80 },
            attrs: node.getAttrs() || cell.attrs || {},
            data: {
              ...cell.data,
              ...node.getData(),
            },
          }
        }
      }
      return cell
    }
  )

  // 更新当前模块的数据
  modulesData[activeDrawingId.value][moduleId] = moduleDataCopy

  try {
    localStorage.setItem('x6-modules', JSON.stringify(modulesData))
    // console.log('模块数据已保存到localStorage，准备跳转')

    // 导航到模块详情页面
    router.push({
      path: `/graph/realNodeDetail`,
      query: {
        drawingId: activeDrawingId.value,
        moduleId,
      },
    })
  } catch {
    // console.error('保存模块数据到localStorage失败:', error)
    ElMessage.error('保存模块数据失败')
    return
  }
}

// 清理选择状态和隐藏连接桩的通用函数
const cleanupSelectionAndPorts = () => {
  if (!graphRef.value) return

  // 清除选择状态
  graphRef.value.cleanSelection()

  // 清除所有节点和边的选择状态
  graphRef.value.getCells().forEach((cell) => {
    graphRef.value!.unselect(cell)
  })

  // 移除所有工具（变换工具等）
  graphRef.value.getCells().forEach((cell) => {
    if (cell.isNode()) {
      cell.removeTools()
    }
    if (cell.isEdge()) {
      cell.removeTools()
    }
  })

  // 隐藏所有连接桩
  setTimeout(() => {
    const container = document.getElementById('graph-container')
    if (container) {
      const ports = container.querySelectorAll('.x6-port-body') as NodeListOf<SVGElement>
      for (let i = 0, len = ports.length; i < len; i += 1) {
        ports[i].style.visibility = 'hidden'
      }

      // 清除可能残留的选择框和变换工具，但不影响标签
      const selectionSelectors = [
        '.x6-widget-selection',
        '.x6-widget-selection-box',
        '.x6-widget-selection-inner',
        '.x6-widget-selection-rubberband',
        '.x6-widget-transform',
        '.x6-selection-box',
        '.x6-widget-boundary',
        '.x6-widget-vertices',
        '.x6-widget-segments',
      ].join(',')

      const selections = container.querySelectorAll(selectionSelectors)

      for (let i = 0, len = selections.length; i < len; i += 1) {
        const element = selections[i] as HTMLElement
        if (element && !element.querySelector('text')) {
          // 只隐藏不包含文本元素的选择框，避免影响标签
          element.style.display = 'none'
          element.style.visibility = 'hidden'
          element.style.opacity = '0'
        }
      }
    }
  }, 100)
}

// 从子页面返回时更新模块链接桩
const updateModulePorts = (moduleId: string, portCount: number, portConnectorData?: any[]) => {
  if (!graphRef.value) {
    console.warn('updateModulePorts: 图表引用不存在')
    return
  }

  const moduleNode = graphRef.value.getCellById(moduleId)
  if (!moduleNode) {
    console.warn(`updateModulePorts: 找不到模块节点 ${moduleId}`)
    return
  }

  console.log(`updateModulePorts: 更新模块 ${moduleId} 的端口数量为 ${portCount}`, { portConnectorData })

  // 清除现有端口
  moduleNode.prop('ports/items', [])

  // 根据端口数量动态创建端口
  if (portCount > 0) {
    const ports = []
    const portGroups = {
      left: {
        position: 'left',
        attrs: {
          circle: {
            r: 6,
            magnet: true,
            stroke: '#1890FF',
            strokeWidth: 2,
            fill: '#E6F7FF',
            style: { visibility: 'hidden' },
          },
          text: {
            fill: '#000000',
            fontSize: 12,
            fontWeight: 'bold',
            textAnchor: 'end',
            textVerticalAnchor: 'middle',
            pointerEvents: 'none',
            stroke: 'white',
            strokeWidth: 3,
            paintOrder: 'stroke',
            refX: '0%',
            refX2: -8,
          },
        },
        label: {
          position: 'left',
        },
      },
      right: {
        position: 'right',
        attrs: {
          circle: {
            r: 6,
            magnet: true,
            stroke: '#1890FF',
            strokeWidth: 2,
            fill: '#E6F7FF',
            style: { visibility: 'hidden' },
          },
          text: {
            fill: '#000000',
            fontSize: 12,
            fontWeight: 'bold',
            textAnchor: 'start',
            textVerticalAnchor: 'middle',
            pointerEvents: 'none',
            stroke: 'white',
            strokeWidth: 3,
            paintOrder: 'stroke',
            refX: '100%',
            refX2: 8,
          },
        },
        label: {
          position: 'right',
        },
      },
    }

    // 添加端口组配置
    moduleNode.prop('ports/groups', portGroups)

    // 根据端口数量在左右两侧分布端口
    const leftPorts = Math.ceil(portCount / 2)
    const rightPorts = portCount - leftPorts

    // 添加左侧端口
    for (let i = 0; i < leftPorts; i++) {
      const portId = `left-port-${i}`
      const portConfig: any = { group: 'left', id: portId }

      // 如果有连接桩数据，尝试获取对应的引脚文字
      if (portConnectorData && portConnectorData[i]) {
        const portConnector = portConnectorData[i]
        const pinText = extractPortConnectorPinText(portConnector)
        if (pinText) {
          portConfig.attrs = {
            text: {
              text: pinText,
            },
          }
          console.log(`设置左侧端口 ${portId} 文字: ${pinText}`)
        }
      }

      ports.push(portConfig)
    }

    // 添加右侧端口
    for (let i = 0; i < rightPorts; i++) {
      const portId = `right-port-${i}`
      const portConfig: any = { group: 'right', id: portId }

      // 如果有连接桩数据，尝试获取对应的引脚文字
      const connectorIndex = leftPorts + i
      if (portConnectorData && portConnectorData[connectorIndex]) {
        const portConnector = portConnectorData[connectorIndex]
        const pinText = extractPortConnectorPinText(portConnector)
        if (pinText) {
          portConfig.attrs = {
            text: {
              text: pinText,
            },
          }
          console.log(`设置右侧端口 ${portId} 文字: ${pinText}`)
        }
      }

      ports.push(portConfig)
    }

    moduleNode.prop('ports/items', ports)
    console.log(`updateModulePorts: 成功创建 ${ports.length} 个端口 (左侧: ${leftPorts}, 右侧: ${rightPorts})`)
  } else {
    console.log('updateModulePorts: 端口数量为0，清除所有端口')
  }

  // 更新模块数据中的端口数量
  const drawingModules = modules.value.get(activeDrawingId.value)
  if (drawingModules && drawingModules.has(moduleId)) {
    const moduleData = drawingModules.get(moduleId)
    if (moduleData) {
      moduleData.portCount = portCount
      console.log(`updateModulePorts: 更新模块数据中的端口数量: ${portCount}`)
    }
  } else {
    console.warn(`updateModulePorts: 找不到模块数据 ${moduleId}`)
  }
}

// 从连接桩节点数据中提取引脚文字
const extractPortConnectorPinText = (portConnectorData: any): string => {
  try {
    // 查找引脚数据中的文字信息
    if (portConnectorData.data && portConnectorData.data.parameterValues) {
      const paramValues = portConnectorData.data.parameterValues

      // 查找引脚相关的参数值
      for (const group in paramValues) {
        const groupData = paramValues[group]
        for (const key in groupData) {
          if (key.includes('pin') || key.includes('引脚') || key.includes('center')) {
            const value = groupData[key]
            if (typeof value === 'string' && value.trim()) {
              return value.trim()
            }
          }
        }
      }
    }

    // 备用方案：查找端口属性中的文字
    if (portConnectorData.ports && portConnectorData.ports.items) {
      for (const portItem of portConnectorData.ports.items) {
        if (portItem.attrs && portItem.attrs.text && portItem.attrs.text.text) {
          return portItem.attrs.text.text
        }
      }
    }

    return ''
  } catch (error) {
    console.error('提取连接桩引脚文字时出错:', error)
    return ''
  }
}

// 从子页面返回时加载最新的模块数据
const loadUpdatedModules = () => {
  // 检查localStorage中是否有保存的模块数据
  const modulesStr = localStorage.getItem('x6-modules')
  if (!modulesStr) return false

  try {
    const modulesData = JSON.parse(modulesStr)
    let hasUpdates = false

    console.log('开始处理模块更新:', modulesData)

    // 遍历所有图纸的模块数据
    for (const drawingId in modulesData) {
      const numDrawingId = Number(drawingId)

      // 确保当前图纸存在模块map
      if (!modules.value.has(numDrawingId)) {
        modules.value.set(numDrawingId, new Map())
      }

      const drawingModulesMap = modules.value.get(numDrawingId)!

      // 遍历该图纸的所有模块
      for (const moduleId in modulesData[drawingId]) {
        const updatedModuleData = modulesData[drawingId][moduleId]

        // 检查当前画布是否已有该模块节点
        if (drawingModulesMap.has(moduleId) && graphRef.value) {
          const existingModule = drawingModulesMap.get(moduleId)
          const moduleNode = graphRef.value.getCellById(moduleId)

          // 如果找到现有模块和节点，更新数据
          if (existingModule && moduleNode) {
            // 计算实际的端口连接器数量（只计算isPortConnector=true的节点）
            const portConnectorCells = updatedModuleData.cells
              ? updatedModuleData.cells.filter((cell: any) => cell.data && cell.data.isPortConnector === true)
              : []
            const actualPortCount = portConnectorCells.length

            console.log(`更新模块 ${existingModule.name}:`, {
              原端口数量: existingModule.portCount,
              新端口数量: actualPortCount,
              cells数量: updatedModuleData.cells?.length || 0,
              端口连接器: portConnectorCells.map((cell: any) => ({
                id: cell.id,
                position: cell.data?.position,
                isPortConnector: cell.data?.isPortConnector,
              })),
            })

            // 更新模块数据
            existingModule.cells = updatedModuleData.cells || []
            existingModule.portCount = actualPortCount

            // 如果有属性数据，也更新它
            if (updatedModuleData.properties) {
              existingModule.properties = updatedModuleData.properties
            }

            // 更新其他元数据
            existingModule.name = updatedModuleData.name || existingModule.name
            existingModule.description = updatedModuleData.description || existingModule.description

            // 更新模块节点的显示属性
            moduleNode.attr('label/text', existingModule.name)
            moduleNode.setData({
              ...moduleNode.getData(),
              name: existingModule.name,
              properties: {
                ...moduleNode.getData()?.properties,
                name: existingModule.name,
              },
            })

            // 更新模块节点的端口配置，传递连接桩数据
            updateModulePorts(moduleId, actualPortCount, portConnectorCells)

            hasUpdates = true

            // 如果当前正在显示这个图纸，显示更新信息
            if (numDrawingId === activeDrawingId.value) {
              if (actualPortCount > 0) {
                ElMessage.success(`模块 "${existingModule.name}" 已更新，端口数量: ${actualPortCount}`)
              } else {
                ElMessage.info(`模块 "${existingModule.name}" 已更新，无端口连接`)
              }
            }
          }
        } else if (!drawingModulesMap.has(moduleId)) {
          // 模块不存在但有数据更新
          console.log('检测到新模块数据，但主页面无对应节点:', moduleId)

          // 检查画布中是否存在该节点但未在模块Map中记录
          if (graphRef.value && graphRef.value.getCellById(moduleId)) {
            console.warn(`发现数据不一致：画布中存在节点 ${moduleId} 但模块Map中没有记录`)

            // 尝试修复数据不一致问题
            const existingNode = graphRef.value.getCellById(moduleId)
            if (existingNode && existingNode.isNode()) {
              const actualPortCount = updatedModuleData.cells
                ? updatedModuleData.cells.filter((cell: any) => cell.data && cell.data.isPortConnector === true).length
                : 0

              // 重新创建模块记录
              const moduleRecord = {
                id: moduleId,
                name: updatedModuleData.name || '未命名模块',
                description: updatedModuleData.description || '',
                cells: updatedModuleData.cells || [],
                portCount: actualPortCount,
                properties: updatedModuleData.properties || {},
                node: existingNode,
              }

              drawingModulesMap.set(moduleId, moduleRecord)

              // 获取连接桩数据
              const portConnectorCells = updatedModuleData.cells
                ? updatedModuleData.cells.filter((cell: any) => cell.data && cell.data.isPortConnector === true)
                : []

              // 更新模块节点的端口配置，传递连接桩数据
              updateModulePorts(moduleId, actualPortCount, portConnectorCells)

              hasUpdates = true
              console.log(`已修复模块数据不一致问题: ${moduleId}`)
            }
          }
          // 如果画布中也没有该节点，则忽略（不创建新模块，避免重复问题）
        }
      }
    }

    // 清除localStorage中的模块数据
    localStorage.removeItem('x6-modules')

    console.log('模块更新处理完成，有更新:', hasUpdates)
    return hasUpdates
  } catch (error) {
    console.error('加载更新的模块数据失败:', error)
    return false
  }
}

// 清理重复的模块节点
const cleanupDuplicateModules = () => {
  if (!graphRef.value) return

  try {
    const allNodes = graphRef.value.getNodes()
    const moduleNodes = allNodes.filter((node) => node.shape === 'module-node' || node.getData()?.isModule)

    // 首先按节点ID去重，确保没有相同ID的节点
    const idMap = new Map<string, any[]>()
    moduleNodes.forEach((node) => {
      const nodeId = node.id
      if (!idMap.has(nodeId)) {
        idMap.set(nodeId, [])
      }
      idMap.get(nodeId)!.push(node)
    })

    // 删除相同ID的重复节点（保留第一个）
    let removedByIdCount = 0
    for (const [nodeId, nodes] of idMap) {
      if (nodes.length > 1) {
        // console.warn(`发现相同ID的重复模块: ${nodeId}, 数量: ${nodes.length}`)
        // 保留第一个，删除其余的
        for (let i = 1; i < nodes.length; i++) {
          const nodeToRemove = nodes[i]
          // console.log(`删除重复ID模块节点: ${nodeToRemove.id}`)
          graphRef.value?.removeNode(nodeToRemove)
          removedByIdCount++
        }
      }
    }

    // 再次获取去重后的模块节点，按位置和名称查找重复
    const remainingNodes = graphRef.value.getNodes().filter((node) => node.shape === 'module-node' || node.getData()?.isModule)
    const positionMap = new Map<string, any[]>()

    remainingNodes.forEach((node) => {
      const position = node.getPosition()
      const name = node.attr('label/text') || '未知'
      // 使用更精确的位置匹配（允许5像素的误差）
      const roundedX = Math.round(position.x / 5) * 5
      const roundedY = Math.round(position.y / 5) * 5
      const key = `${name}-${roundedX}-${roundedY}`

      if (!positionMap.has(key)) {
        positionMap.set(key, [])
      }
      positionMap.get(key)!.push(node)
    })

    // 删除重复位置的节点（保留第一个）
    let removedByPositionCount = 0
    for (const [_key, nodes] of positionMap) {
      if (nodes.length > 1) {
        // console.warn(`发现重复位置的模块: ${_key}, 数量: ${nodes.length}`)
        // 保留第一个，删除其余的
        for (let i = 1; i < nodes.length; i++) {
          const nodeToRemove = nodes[i]
          // console.log(`删除重复位置模块节点: ${nodeToRemove.id}`)
          graphRef.value?.removeNode(nodeToRemove)
          removedByPositionCount++
        }
      }
    }

    const totalRemoved = removedByIdCount + removedByPositionCount
    if (totalRemoved > 0) {
      // console.log(`已清理 ${totalRemoved} 个重复的模块节点 (ID重复: ${removedByIdCount}, 位置重复: ${removedByPositionCount})`)
      ElMessage.info(`已清理 ${totalRemoved} 个重复的模块节点`)
    }
  } catch (error) {
    console.error('清理重复模块时出错:', error)
  }
}

// 在模块上使用新的调试功能，显示模块包含的元素数量
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const visualizeModuleContent = (moduleId: string) => {
  if (!graphRef.value) return

  // 获取当前图纸的模块Map
  const drawingModulesMap = modules.value.get(activeDrawingId.value)
  if (!drawingModulesMap || !drawingModulesMap.has(moduleId)) return

  // 获取模块数据
  const moduleData = drawingModulesMap.get(moduleId)
  if (!moduleData || !moduleData.cells) return

  // 创建一个临时元素来显示模块中的元素数量
  const node = graphRef.value.getCellById(moduleId)
  if (!node || !node.isNode()) return

  // 获取模块中的元素数量
  const elementCount = moduleData.cells.length

  // 在模块节点上显示一个临时的气泡提示
  const nodeElement = node as Node
  const position = nodeElement.getPosition()
  const size = nodeElement.getSize()

  // 创建一个临时节点显示信息
  const infoNode = graphRef.value.addNode({
    shape: 'rect',
    x: position.x + size.width / 2 - 60,
    y: position.y - 40,
    width: 120,
    height: 30,
    attrs: {
      body: {
        fill: '#4CAF50',
        stroke: '#2E7D32',
        strokeWidth: 1,
        rx: 15,
        ry: 15,
      },
      text: {
        text: `包含 ${elementCount} 个元素`,
        fill: '#FFF',
        fontSize: 12,
        fontWeight: 'bold',
      },
    },
    zIndex: 999,
  })

  // 3秒后自动删除提示
  setTimeout(() => {
    if (graphRef.value) {
      graphRef.value.removeNode(infoNode)
    }
  }, 3000)
}

// 添加激活时的处理，确保在从子页面返回时更新模块数据
const lastRoute = ref('')

// 防重复处理的标记
const isProcessingModuleUpdate = ref(false)

const router = useRouter()

// 添加路由守卫，监听路由变化
router.afterEach((to, from) => {
  // 记录上一个路由路径
  lastRoute.value = from.path

  // 如果从模块详情页返回，则刷新模块数据
  if (to.path === '/graph/antvX6Demo' && from.path.includes('/graph/realNodeDetail')) {
    // 防止重复处理
    if (isProcessingModuleUpdate.value) {
      console.log('模块更新正在处理中，跳过重复请求')
      return
    }

    isProcessingModuleUpdate.value = true

    // 延迟执行，确保组件已更新
    setTimeout(() => {
      try {
        console.log('从模块详情页返回，开始更新模块数据')

        // 第一步：先清理重复的模块节点
        console.log('清理重复模块节点...')
        cleanupDuplicateModules()

        // 短暂延迟后加载更新的模块数据
        setTimeout(() => {
          // 第二步：加载更新的模块数据
          // console.log('开始加载更新的模块数据...')
          const hasUpdates = loadUpdatedModules()

          // 第三步：如果有更新，验证端口配置并保存
          if (hasUpdates && graphRef.value) {
            // 验证并修复所有模块的端口配置
            const drawingModules = modules.value.get(activeDrawingId.value)
            if (drawingModules) {
              for (const [moduleId, moduleData] of drawingModules) {
                const moduleNode = graphRef.value.getCellById(moduleId)
                if (moduleNode && moduleData.portCount !== undefined) {
                  // console.log(`验证模块 ${moduleData.name} 的端口配置: ${moduleData.portCount}`)
                  updateModulePorts(moduleId, moduleData.portCount)
                }
              }
            }

            // 保存当前图纸状态
            saveGraphContent()
          }

          // 重置处理标记
          setTimeout(() => {
            isProcessingModuleUpdate.value = false
          }, 1500)
        }, 100)
      } catch {
        isProcessingModuleUpdate.value = false
      }
    }, 100)
  }
})

// 导出选中节点为SVG
const exportSelectedNodesAsSVG = () => {
  if (!graphRef.value) return

  try {
    // 创建导出插件实例
    const graph = graphRef.value

    // 获取选中的单元格
    const selectedCells = graph.getSelectedCells()

    // 获取画布中所有节点
    const allNodes = graph.getNodes()
    const allEdges = graph.getEdges()
    const allCells = [...allNodes, ...allEdges]

    // 检查画布是否为空，如果为空则提示无法导出
    if (allCells.length === 0) {
      ElMessage.warning('画布为空，无法导出SVG图片')
      return
    }

    // 创建新的导出插件实例，设置高质量导出选项
    const exportPlugin = new Export()
    graph.use(exportPlugin)

    // 设置文件名
    const fileName = `图纸导出_${new Date().toISOString().slice(0, 10)}`

    // 修复transformer节点的图像引用问题
    const fixTransformerImagePaths = () => {
      // 查找所有custom-transformer节点
      const transformerNodes = graph
        .getNodes()
        .filter((node) => node.shape === 'custom-transformer' || (node.attrs && node.attrs.image && node.attrs.image['xlink:href']))

      // 临时保存原始图像路径
      const originalPaths = new Map()

      // 对每个transformer节点，将相对路径转为base64或绝对路径
      transformerNodes.forEach((node) => {
        const imagePath = node.attr('image/xlink:href')
        if (typeof imagePath === 'string' && imagePath.startsWith('/')) {
          // 保存原始路径
          originalPaths.set(node.id, imagePath)

          // 将相对路径转为绝对路径
          const absolutePath = globalThis.location.origin + imagePath
          node.attr('image/xlink:href', absolutePath)
        }
      })

      // 返回一个函数用于还原路径
      return () => {
        transformerNodes.forEach((node) => {
          if (originalPaths.has(node.id)) {
            node.attr('image/xlink:href', originalPaths.get(node.id))
          }
        })
      }
    }

    // 应用修复并获取还原函数
    const restoreImagePaths = fixTransformerImagePaths()

    if (selectedCells.length > 0) {
      // 如果有选中的单元格，只导出选中的部分
      const cellsBBox = graph.getCellsBBox(selectedCells)
      if (cellsBBox) {
        // 为选中区域添加一些padding，避免内容被裁剪
        const padding = 20
        const expandedViewBox = {
          x: cellsBBox.x - padding,
          y: cellsBBox.y - padding,
          width: cellsBBox.width + padding * 2,
          height: cellsBBox.height + padding * 2,
        }

        // 导出选项 - 确保包含图像
        const exportOptions = {
          viewBox: expandedViewBox,
          serializeImages: true,
          copyStyles: true,
          preserveDimensions: true,
          beforeSerialize: (svg: SVGSVGElement) => {
            // 确保所有图像元素都有正确的尺寸和位置
            const images = svg.querySelectorAll('image')
            images.forEach((img: SVGImageElement) => {
              // 确保图像元素属性完整
              if (!img.getAttribute('width')) {
                img.setAttribute('width', '60')
              }
              if (!img.getAttribute('height')) {
                img.setAttribute('height', '60')
              }
            })
            return svg
          },
        }

        // 导出SVG
        exportPlugin.exportSVG(fileName, exportOptions)
        ElMessage.success('已导出选中区域为SVG图片')
      } else {
        // 找不到边界框，导出整个图
        exportPlugin.exportSVG(fileName, {
          serializeImages: true,
          copyStyles: true,
          preserveDimensions: true,
        })
        ElMessage.success('已导出选中内容为SVG图片')
      }
    } else if (allCells.length > 0) {
      // 没有选中的单元格但画布有内容，导出整个画布
      const allCellsBBox = graph.getCellsBBox(allCells)

      if (allCellsBBox) {
        // 为画布内容添加padding
        const padding = 50
        const expandedViewBox = {
          x: allCellsBBox.x - padding,
          y: allCellsBBox.y - padding,
          width: allCellsBBox.width + padding * 2,
          height: allCellsBBox.height + padding * 2,
        }

        const exportOptions = {
          viewBox: expandedViewBox,
          serializeImages: true,
          copyStyles: true,
          preserveDimensions: true,
          backgroundColor: backgroundColor.value || '#FFFFFF',
          beforeSerialize: (svg: SVGSVGElement) => {
            // 设置SVG属性确保所有内容可见
            svg.setAttribute('width', `${allCellsBBox.width + padding * 2}px`)
            svg.setAttribute('height', `${allCellsBBox.height + padding * 2}px`)

            // 确保所有图像元素都有正确的尺寸和位置
            const images = svg.querySelectorAll('image')
            images.forEach((img: SVGImageElement) => {
              if (!img.getAttribute('width')) {
                img.setAttribute('width', '60')
              }
              if (!img.getAttribute('height')) {
                img.setAttribute('height', '60')
              }
            })

            // 添加背景色矩形作为第一个子元素
            const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
            rect.setAttribute('width', '100%')
            rect.setAttribute('height', '100%')
            rect.setAttribute('fill', backgroundColor.value || '#FFFFFF')
            if (svg.firstChild) {
              svg.insertBefore(rect, svg.firstChild)
            } else {
              svg.appendChild(rect)
            }

            return svg
          },
        }

        // 导出SVG
        exportPlugin.exportSVG(fileName, exportOptions)
        ElMessage.success('已导出全部图形为SVG图片')
      } else {
        // 找不到边界框，导出当前视图
        exportPlugin.exportSVG(fileName, {
          serializeImages: true,
          copyStyles: true,
          preserveDimensions: true,
          beforeSerialize: (svg: SVGSVGElement) => {
            // 添加背景色矩形作为第一个子元素
            const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
            rect.setAttribute('width', '100%')
            rect.setAttribute('height', '100%')
            rect.setAttribute('fill', backgroundColor.value || '#FFFFFF')
            if (svg.firstChild) {
              svg.insertBefore(rect, svg.firstChild)
            } else {
              svg.appendChild(rect)
            }
            return svg
          },
        })
        ElMessage.success('已导出当前视图为SVG图片')
      }
    } else {
      // 画布完全空白，导出当前空白视图
      exportPlugin.exportSVG(fileName, {
        serializeImages: true,
        copyStyles: true,
        preserveDimensions: true,
        beforeSerialize: (svg: SVGSVGElement) => {
          // 添加背景色矩形作为第一个子元素
          const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
          rect.setAttribute('width', '100%')
          rect.setAttribute('height', '100%')
          rect.setAttribute('fill', backgroundColor.value || '#FFFFFF')
          if (svg.firstChild) {
            svg.insertBefore(rect, svg.firstChild)
          } else {
            svg.appendChild(rect)
          }
          return svg
        },
      })
      ElMessage.success('已导出空白画布为SVG图片')
    }

    // 导出后恢复原始路径
    restoreImagePaths()

    // 导出完成后卸载插件，避免内存泄漏
    graph.disposePlugins('export')
  } catch {
    ElMessage.error('导出SVG图片失败')
  }
}

// 选择组右键菜单选项
const selectionGroupMenuOptions = [
  {
    label: '删除选择组',
    value: 'delete-selection-group',
    icon: 'trash',
  },
]

// 选择组右键菜单状态
const selectionGroupMenuVisible = ref(false)
const selectionGroupMenuPosition = ref({ x: 0, y: 0 })
const selectedGroupId = ref<string | null>(null)

// 显示选择组右键菜单
const showSelectionGroupContextMenu = (event: MouseEvent, groupId: string) => {
  event.preventDefault()
  selectedGroupId.value = groupId
  selectionGroupMenuPosition.value = { x: event.clientX, y: event.clientY }
  selectionGroupMenuVisible.value = true
}

// 处理选择组右键菜单操作
const handleSelectionGroupMenuAction = (action: string) => {
  if (action === 'delete-selection-group' && selectedGroupId.value) {
    deleteSelectionGroupById(selectedGroupId.value)
  }

  // 关闭菜单
  selectionGroupMenuVisible.value = false
}

// 通过ID删除选择组
const deleteSelectionGroupById = (groupId: string) => {
  if (!graphRef.value) return

  // 获取当前图纸的选择组
  const drawingGroups = selectionGroups.value.get(activeDrawingId.value)
  if (!drawingGroups) return

  const groupData = drawingGroups.get(groupId)
  if (!groupData) return

  // 删除节点
  const group = graphRef.value.getCellById(groupId)
  if (group) {
    graphRef.value.removeCell(group)
  }

  // 从存储中删除
  drawingGroups.delete(groupId)

  // 如果删除的是当前活动组，重置当前选择组
  if (activeSelectionGroup.value && activeSelectionGroup.value.id === groupId) {
    activeSelectionGroup.value = null
    isEditingGroup.value = false
  }

  // 保存图纸内容
  const currentGraphData = graphRef.value.toJSON()
  graphContents.value.set(activeDrawingId.value, currentGraphData)
}

// 切换选择组折叠状态
const toggleSelectionGroupsCollapse = () => {
  isSelectionGroupsCollapsed.value = !isSelectionGroupsCollapsed.value
}

// 返回选择组列表
const backToGroupsList = () => {
  activeSelectionGroup.value = null
  isEditingGroup.value = false
}

// 只选择一个组，不进入编辑模式
const selectGroupOnly = (groupId: string) => {
  if (!graphRef.value) return

  // 获取当前图纸的选择组
  const drawingGroups = selectionGroups.value.get(activeDrawingId.value)
  if (!drawingGroups) return

  const groupData = drawingGroups.get(groupId)
  if (!groupData) return

  // 设置为活动组，但不进入编辑模式
  activeSelectionGroup.value = groupData

  // 选中组节点，但不选中组内的元素，以允许使用selection框选
  const group = graphRef.value.getCellById(groupId)
  if (group) {
    // 选中组，但不清除当前已有的选择，允许多选
    graphRef.value.select(group, { additional: true })
  }
}

// 编辑一个组（双击时调用）
const editGroup = (groupId: string) => {
  if (!graphRef.value) return

  // 获取当前图纸的选择组
  const drawingGroups = selectionGroups.value.get(activeDrawingId.value)
  if (!drawingGroups) return

  const groupData = drawingGroups.get(groupId)
  if (!groupData) return

  // 设置为活动组并进入编辑模式
  activeSelectionGroup.value = groupData
  isEditingGroup.value = true

  // 更新属性面板值
  groupBackgroundColor.value = groupData.backgroundColor
  groupText.value = groupData.text

  // 选中组节点
  const group = graphRef.value.getCellById(groupId)
  if (group) {
    // 先清除当前选择
    graphRef.value.cleanSelection()

    // 只选中组节点本身，不选中组内成员，避免出现重叠的选择框
    graphRef.value.select(group)
  }
}

// 更新节点标签
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const updateNodeLabel = (value: string) => {
  if (selectedNode.value) {
    console.log('selectedNode.value', selectedNode.value)
    selectedNode.value.attr('label/text', value)
  }
}

// 更新节点填充颜色
const updateNodeFill = (value: string | null) => {
  if (selectedNode.value && value !== null) {
    selectedNode.value.attr('body/fill', value)
    nodeFillColor.value = value
  }
}

// 更新节点边框颜色
const updateNodeStroke = (value: string | null) => {
  if (selectedNode.value && value !== null) {
    selectedNode.value.attr('body/stroke', value)
    nodeStrokeColor.value = value
  }
}

// 更新节点边框宽度
const updateNodeStrokeWidth = (value: number | undefined) => {
  if (selectedNode.value && value !== undefined) {
    selectedNode.value.attr('body/strokeWidth', value)
    nodeBorderWidth.value = value
  }
}

// 更新节点文本颜色
const updateNodeLabelColor = (value: string | null) => {
  if (selectedNode.value && value !== null) {
    // 更新节点主标签颜色
    selectedNode.value.attr('label/fill', value)
    selectedNode.value.attr('text/fill', value)

    // 更新响应式变量
    nodeLabelColor.value = value

    // 更新连接桩标签颜色
    const ports = selectedNode.value.getPorts()
    if (ports && ports.length > 0) {
      ports.forEach(port => {
        const portId = port.id
        if (portId) {
          // 获取当前连接桩的文本属性
          const currentText = selectedNode.value.getPortProp(portId, 'attrs/text')
          if (currentText) {
            // 更新连接桩文字标签的颜色
            selectedNode.value.setPortProp(portId, 'attrs/text', {
              ...currentText,
              fill: value
            })
          }
        }
      })
    }
  }
}

// 更新节点文本大小
const updateNodeFontSize = (value: number | undefined) => {
  if (selectedNode.value && value !== undefined) {
    // 更新节点主标签字体大小
    selectedNode.value.attr('label/fontSize', value)
    selectedNode.value.attr('text/fontSize', value)

    // 更新连接桩标签字体大小
    const ports = selectedNode.value.getPorts()
    if (ports && ports.length > 0) {
      ports.forEach(port => {
        const portId = port.id
        if (portId) {
          // 获取当前连接桩的文本属性
          const currentText = selectedNode.value.getPortProp(portId, 'attrs/text')
          if (currentText) {
            // 更新连接桩文字标签的字体大小
            selectedNode.value.setPortProp(portId, 'attrs/text', {
              ...currentText,
              fontSize: value
            })
          }
        }
      })
    }

    // 更新状态变量
    nodeFontSize.value = value

  }
}

// 更新节点位置
const updateNodePosition = (x: number | undefined, y: number | undefined) => {
  if (selectedNode.value) {
    const position = selectedNode.value.getPosition()
    if (x !== undefined) {
      selectedNode.value.setPosition(x, position.y)
      nodeX.value = x
    }
    if (y !== undefined) {
      selectedNode.value.setPosition(position.x, y)
      nodeY.value = y
    }
  }
}

// 更新节点尺寸
const updateNodeSize = (width: number | undefined, height: number | undefined) => {
  if (selectedNode.value) {
    const size = selectedNode.value.getSize()
    if (width !== undefined && height !== undefined) {
      selectedNode.value.resize(width, height)
      nodeWidth.value = width
      nodeHeight.value = height
    } else if (width !== undefined) {
      selectedNode.value.resize(width, size.height)
      nodeWidth.value = width
    } else if (height !== undefined) {
      selectedNode.value.resize(size.width, height)
      nodeHeight.value = height
    }
  }
}

// 重设节点大小
const resetNodeSize = () => {
  if (selectedNode.value) {
    // 重置为默认大小，根据实际需求调整
    selectedNode.value.resize(100, 60)
  }
}

// 置于顶层
const bringToFront = () => {
  if (selectedNode.value) {
    selectedNode.value.toFront()
  }
}

// 置于底层
const sendToBack = () => {
  if (selectedNode.value) {
    selectedNode.value.toBack()
  }
}

// 更新节点字体 - 全面调试版本
const updateNodeFontFamily = async (value: string) => {
  if (!selectedNode.value || !value) {
    console.log('❌ 节点或字体值无效')
    return
  }

  try {
    selectedNode.value.attr('label/fontFamily', value)
    selectedNode.value.attr('text/fontFamily', value)
    const nodeView = graphRef.value?.findView(selectedNode.value)
    if (nodeView && nodeView.container) {

      // 查找所有可能的文本元素
      const textElements = nodeView.container.querySelectorAll('text')
      const tspanElements = nodeView.container.querySelectorAll('tspan')
      const imageElements = nodeView.container.querySelectorAll('image')

      const allTextElements = [...textElements, ...tspanElements]

      allTextElements.forEach((textEl, index) => {
        const originalFont = textEl.getAttribute('font-family')
        const currentText = textEl.textContent?.trim()
        const selector = textEl.getAttribute('data-selector') || textEl.className || '无'


        // 使用多种方式设置字体
        textEl.setAttribute('font-family', value)
        textEl.style.fontFamily = value
        textEl.style.setProperty('font-family', value, 'important')
      })

      if (imageElements.length > 0) {
        for (let i = 0; i < imageElements.length; i++) {
          const imgEl = imageElements[i]
          const href = imgEl.getAttribute('href') || imgEl.getAttribute('xlink:href')

          if (href && !href.startsWith('blob:')) {
            try {
              await updateSVGNodeText(selectedNode.value, 'fontFamily', value)
            } catch (svgError) {
            }
          }
        }
      }
    } else {
      console.log('❌ 未找到节点视图或容器')
    }


    // 更新状态变量
    nodeFontFamily.value = value


    setTimeout(() => {
      if (selectedNode.value && graphRef.value) {
        const nodeView = graphRef.value.findView(selectedNode.value)
        if (nodeView && nodeView.container) {
          const finalTextElements = nodeView.container.querySelectorAll('text, tspan')


          finalTextElements.forEach((textEl, index) => {
            const computedFont = window.getComputedStyle(textEl).fontFamily
            const attrFont = textEl.getAttribute('font-family')

            // 最后确保字体设置正确
            if (attrFont !== value) {
              textEl.setAttribute('font-family', value)
              textEl.style.fontFamily = value
            }
          })
        }
      }
    }, 200)

  } catch (error) {
    console.error('❌ 更新字体时出错:', error)
  }
}

// 导出为JSON文件
const exportAsJSON = () => {
  if (!graphRef.value) return

  try {
    // 获取当前画布的完整数据
    const graph = graphRef.value
    const jsonData = graph.toJSON()

    // 检查是否有内容可以导出
    if (!jsonData.cells || jsonData.cells.length === 0) {
      ElMessage.warning('画布为空，无法导出JSON数据')
      return
    }

    // 处理所有节点和边的属性，确保导出时包含完整的属性信息
    jsonData.cells = jsonData.cells.map((cell: any) => {
      const cellInstance = graph.getCellById(cell.id)

      if (cell.shape === 'edge' || (!cell.shape && cell.source && cell.target)) {
        // 处理边的属性
        if (cellInstance && cellInstance.isEdge()) {
          const router = cellInstance.getRouter()
          const connector = cellInstance.getConnector()
          const labels = cellInstance.getLabels()

          return {
            ...cell,
            // 保存格式属性
            edgeProperties: {
              routerType: router?.name === 'orth' ? '正交' : '无',
              connectorType: connector?.name === 'rounded' ? '圆角' : connector?.name === 'smooth' ? '平滑' : '无',
              strokeColor: cellInstance.attr('line/stroke') || '#000000',
              strokeWidth: cellInstance.attr('line/strokeWidth') || 2,
              fillColor: labels[0]?.attrs?.rect?.fill || '#ffffff',
              textColor: labels[0]?.attrs?.text?.fill || '#333333',
              fontFamily: labels[0]?.attrs?.text?.fontFamily || 'Arial',
              fontSize: labels[0]?.attrs?.text?.fontSize || 12
            }
          }
        }
      } else {
        // 处理节点的属性
        const nodeData = cell.data || {}
        const nodeConfig = getNodeConfigurationFromJSON(cell.shape, nodeRegistrationsFromJSON.value)

        // 统一收集所有属性到propertiesData的顶层结构中
        const propertiesData: Record<string, any> = {}

        // 1. 先从节点现有数据中提取属性
        if (nodeData.propertiesData) {
          Object.assign(propertiesData, nodeData.propertiesData)
        }

        // 2. 从旧的数据结构中提取（向后兼容）
        if (nodeData.parameterGroups) {
          Object.keys(nodeData.parameterGroups).forEach(groupKey => {
            const groupData = nodeData.parameterGroups[groupKey]
            if (groupData && typeof groupData === 'object') {
              Object.assign(propertiesData, groupData)
            }
          })
        }

        // 3. 从根级别属性中提取（向后兼容）
        Object.keys(nodeData).forEach(key => {
          if (key !== 'propertiesData' && key !== 'parameterGroups' &&
              key !== 'label' && typeof nodeData[key] !== 'object') {
            propertiesData[key] = nodeData[key]
          }
        })

        // 4. 从节点实例中获取当前的数据状态
        if (cellInstance && cellInstance.isNode()) {
          const instanceData = cellInstance.getData() || {}

          // 从实例的propertiesData中提取
          if (instanceData.propertiesData) {
            Object.assign(propertiesData, instanceData.propertiesData)
          }

          // 从实例的其他数据中提取
          Object.keys(instanceData).forEach(key => {
            if (key !== 'propertiesData' && key !== 'parameterGroups' &&
                key !== 'label' && typeof instanceData[key] !== 'object') {
              propertiesData[key] = instanceData[key]
            }
          })
        }

        // 5. 获取节点标签 - 优化标签获取逻辑
        let nodeLabel = nodeData.label
        if (!nodeLabel && cellInstance && cellInstance.isNode()) {
          // 从节点实例中获取标签
          const instanceData = cellInstance.getData() || {}
          nodeLabel = instanceData.label
        }
        if (!nodeLabel) {
          // 从attrs中获取当前显示的文本
          nodeLabel = cell.attrs?.text?.text
        }
        if (!nodeLabel && nodeConfig) {
          // 从stencilConfig获取标签，如果没有则使用name
          if (nodeConfig.stencilConfig && nodeConfig.stencilConfig.length > 0) {
            nodeLabel = nodeConfig.stencilConfig[0].label || nodeConfig.name
          } else {
            nodeLabel = nodeConfig.name
          }
        }

        // 6. 确保关键属性有默认值
        if (nodeConfig && nodeConfig.properties) {
          nodeConfig.properties.forEach(prop => {
            if (prop && prop.key && propertiesData[prop.key] === undefined && prop.defaultValue !== undefined) {
              propertiesData[prop.key] = prop.defaultValue
            }
          })
        }

        // 7. 从参数组配置中补充默认值
        if (nodeConfig && nodeConfig.parameterGroups) {
          nodeConfig.parameterGroups.forEach(group => {
            if (group && group.properties && Array.isArray(group.properties)) {
              group.properties.forEach(prop => {
                if (prop && prop.key && propertiesData[prop.key] === undefined && prop.defaultValue !== undefined) {
                  propertiesData[prop.key] = prop.defaultValue
                }
              })
            }
          })
        }

        // 8. 获取格式属性（attrs）
        const formatAttrs = cell.attrs || {}

        // 返回优化后的节点数据结构 - 保留propertiesData，消除重复
        return {
          ...cell,
          data: {
            // 保留必要的标识信息
            label: nodeLabel || '',
            // 统一的属性数据结构
            propertiesData,
          },
          // 保留格式属性信息
          ...(Object.keys(formatAttrs).length > 0 && { attrs: formatAttrs })
        }
      }

      return cell
    })

    // 获取当前活动图纸信息
    const currentDrawing = drawings.value.find(d => d.id === activeDrawingId.value)
    if (!currentDrawing) {
      ElMessage.error('无法获取当前图纸信息')
      return
    }

    // 获取当前图纸的属性（只导出当前画布的属性，不是所有图纸的属性）
    const currentDrawingProperties = drawingProperties.value.get(activeDrawingId.value) || {
      backgroundColor: backgroundColor.value,
      gridType: gridType.value,
      gridColor: gridColor.value,
      pageLineVisible: pageLineVisible.value,
      referenceStandardsVisible: referenceStandardsVisible.value,
      elementsStandard: elementsStandard.value,
      guidelineStandard: guidelineStandard.value,
      canvasWidth: canvasWidth.value,
      canvasHeight: canvasHeight.value,
      baseCanvasWidth: baseCanvasWidth.value,
      baseCanvasHeight: baseCanvasHeight.value,
    }

    // 获取当前图纸的选择组数据
    const currentSelectionGroups = selectionGroups.value.get(activeDrawingId.value)
    const selectionGroupsData = currentSelectionGroups ? Object.fromEntries(currentSelectionGroups) : {}

    // 获取当前图纸的模块数据
    const currentModules = modules.value.get(activeDrawingId.value)
    const modulesData = currentModules ? Object.fromEntries(
      Array.from(currentModules.entries()).map(([moduleId, moduleData]) => [
              moduleId,
              {
                ...moduleData,
                cells: moduleData.cells || [],
                name: moduleData.name,
                description: moduleData.description,
                type: moduleData.type,
                category: moduleData.category,
                permission: moduleData.permission,
                projectId: moduleData.projectId,
                resourceId: moduleData.resourceId,
                modelId: moduleData.modelId,
                createdAt: moduleData.createdAt || new Date().toISOString(),
                updatedAt: new Date().toISOString(),
              },
            ])
    ) : {}

        // 构建优化后的导出数据格式 - canvasInfo作为最外层对象
    const exportData = {
      // 画布基本信息作为最外层属性
      id: currentDrawing.id,
      name: currentDrawing.name,
      date: currentDrawing.date,
        version: '1.0',
        exportedAt: new Date().toISOString(),
        exportedBy: 'AntvX6Demo',
      description: `${currentDrawing.name}的画布数据导出`,

      // 画布内容数据
      canvasData: {
        cells: jsonData.cells || [],
        cellsCount: jsonData.cells?.length || 0
      },

      // 画布属性（只包含当前画布的属性）
      canvasProperties: currentDrawingProperties,

      // 选择组数据（只包含当前画布的选择组）
      selectionGroups: selectionGroupsData,

      // 模块数据（只包含当前画布的模块）
      modules: modulesData,

      // 统计信息
      statistics: {
        nodesCount: jsonData.cells?.filter((cell: any) => cell.shape && cell.shape !== 'edge').length || 0,
        edgesCount: jsonData.cells?.filter((cell: any) => cell.shape === 'edge' || (!cell.shape && cell.source && cell.target)).length || 0,
        modulesCount: Object.keys(modulesData).length,
        selectionGroupsCount: Object.keys(selectionGroupsData).length
      }
    }

    // 转换为字符串并添加格式化
    const jsonString = JSON.stringify(exportData, null, 2)

    // 创建Blob对象
    const blob = new Blob([jsonString], { type: 'application/json' })

    // 创建下载链接
    const url = URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url

    // 使用画布名称作为文件名
    const fileName = `${exportData.name}_${new Date().toISOString().slice(0, 10)}.json`
    link.download = fileName

    // 触发下载
    document.body.appendChild(link)
    link.click()

    // 清理
    document.body.removeChild(link)
    URL.revokeObjectURL(url)

    ElMessage.success(`已导出 ${exportData.name} 的完整数据`)
  } catch (error) {
    console.error('导出JSON时出错:', error)
    ElMessage.error('导出JSON数据失败')
  }
}

// 导入对话框相关状态
const importDialogVisible = ref(false)
const fileInputRef = ref<HTMLInputElement | null>(null)
const selectedFileName = ref('') // 存储选择的文件名
const isDraggingFile = ref(false) // 拖拽状态

// 显示导入对话框
const showImportDialog = () => {
  importDialogVisible.value = true
}

// 触发文件选择
const triggerFileSelect = () => {
  if (fileInputRef.value) {
    fileInputRef.value.click()
  }
}

// 处理文件选择
const handleFileSelect = (event: Event) => {
  const input = event.target as HTMLInputElement
  if (!input.files || input.files.length === 0) return

  const file = input.files[0]

  // 检查文件类型
  if (file.type !== 'application/json' && !file.name.endsWith('.json')) {
    ElMessage.error('请选择JSON格式的文件')
    return
  }

  // 保存选择的文件名
  selectedFileName.value = file.name

  processImportFile(file)
}

// 处理文件拖拽
const handleDrop = (e: DragEvent) => {
  e.preventDefault()
  isDraggingFile.value = false

  if (!e.dataTransfer?.files.length) return

  const file = e.dataTransfer.files[0]

  if (file.type !== 'application/json' && !file.name.endsWith('.json')) {
    ElMessage.error('请选择JSON格式的文件')
    return
  }

  selectedFileName.value = file.name

  processImportFile(file)
}

// 处理导入文件的通用函数
const processImportFile = (file: File) => {
  const reader = new FileReader()

  reader.addEventListener('load', (e) => {
    try {
      const jsonData = JSON.parse(e.target?.result as string)

      // 检查数据格式是否有效 - 适配新的导出格式
      const hasOldFormat = jsonData.cells || jsonData.exportMetadata
      const hasNewFormat = jsonData.canvasData && jsonData.canvasData.cells && jsonData.name

      if (!hasOldFormat && !hasNewFormat) {
        ElMessage.error('JSON数据格式无效，缺少必要字段')
        return
      }

      // 导入数据到当前画布（会自动处理确认提示）
      importJSONData(jsonData)

      // 关闭对话框
      importDialogVisible.value = false

      // 清空文件输入
      if (fileInputRef.value) {
        fileInputRef.value.value = ''
      }
      selectedFileName.value = ''
    } catch (error) {
      console.error('解析JSON文件失败:', error)
      ElMessage.error('解析JSON文件失败，请确保文件格式正确')
    }
  })

  reader.addEventListener('error', () => {
    ElMessage.error('读取文件时出错')
  })

  reader.readAsText(file)
}

// 导入JSON数据到画布
const importJSONData = (jsonData: any) => {
  if (!graphRef.value) return

  try {
    // 检查当前画布是否有内容
    const currentCells = graphRef.value.getCells()
    const hasContent = currentCells && currentCells.length > 0

    // 如果画布有内容，询问用户是否要清空
    if (hasContent) {
      ElMessageBox.confirm('导入数据将清空当前画布内容，是否继续？', '确认导入', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(() => {
          // 用户确认后执行导入
          performImport(jsonData)
        })
        .catch(() => {
          // 用户取消导入
          ElMessage.info('已取消导入')
        })
    } else {
      // 画布为空，直接导入
      performImport(jsonData)
    }
  } catch (error) {
    console.error('导入JSON数据失败:', error)
    ElMessage.error('导入JSON数据失败，请检查数据格式')
  }
}

// 执行实际的导入操作
const performImport = (jsonData: any) => {
  if (!graphRef.value) return

  // 设置导入状态
  const isImporting = true

  try {
    // 检测数据格式类型
    const isNewFormat = jsonData.canvasData && jsonData.canvasData.cells && jsonData.name
    const isOldCompleteExport = jsonData.exportMetadata && jsonData.modules

    if (isNewFormat) {
      // 处理新格式的导出数据
      console.log('检测到新格式数据，正在导入...', jsonData.name)

      // 更新当前图纸信息
      const currentDrawing = drawings.value.find(d => d.id === activeDrawingId.value)
      if (currentDrawing) {
        // 可以选择是否更新图纸名称，这里保持原有名称
        // currentDrawing.name = jsonData.name
        // currentDrawing.date = jsonData.date
      }

      // 导入画布属性到当前图纸
      if (jsonData.canvasProperties) {
        drawingProperties.value.set(activeDrawingId.value, jsonData.canvasProperties)
        // 应用属性到UI
        backgroundColor.value = jsonData.canvasProperties.backgroundColor || defaultProperties.backgroundColor
        gridType.value = jsonData.canvasProperties.gridType || defaultProperties.gridType
        gridColor.value = jsonData.canvasProperties.gridColor || defaultProperties.gridColor
        pageLineVisible.value = jsonData.canvasProperties.pageLineVisible ?? defaultProperties.pageLineVisible
        referenceStandardsVisible.value = jsonData.canvasProperties.referenceStandardsVisible ?? defaultProperties.referenceStandardsVisible
        elementsStandard.value = jsonData.canvasProperties.elementsStandard ?? defaultProperties.elementsStandard
        guidelineStandard.value = jsonData.canvasProperties.guidelineStandard ?? defaultProperties.guidelineStandard
        canvasWidth.value = jsonData.canvasProperties.canvasWidth || defaultProperties.canvasWidth
        canvasHeight.value = jsonData.canvasProperties.canvasHeight || defaultProperties.canvasHeight
        baseCanvasWidth.value = jsonData.canvasProperties.baseCanvasWidth || defaultProperties.baseCanvasWidth
        baseCanvasHeight.value = jsonData.canvasProperties.baseCanvasHeight || defaultProperties.baseCanvasHeight
      }

      // 导入选择组数据到当前图纸
      if (jsonData.selectionGroups && Object.keys(jsonData.selectionGroups).length > 0) {
        const groupsMap = new Map()
        for (const [groupId, groupData] of Object.entries(jsonData.selectionGroups)) {
          groupsMap.set(groupId, groupData)
        }
        selectionGroups.value.set(activeDrawingId.value, groupsMap)
      }

      // 导入模块数据到当前图纸
      if (jsonData.modules && Object.keys(jsonData.modules).length > 0) {
        const modulesMap = new Map()
        for (const [moduleId, moduleData] of Object.entries(jsonData.modules)) {
          // 确保模块数据包含必要的字段
          const completeModuleData = {
            ...(moduleData as any),
            cells: (moduleData as any).cells || [],
            name: (moduleData as any).name || `模块_${moduleId}`,
            description: (moduleData as any).description || '',
            type: (moduleData as any).type || '元件',
            category: (moduleData as any).category || '',
            permission: (moduleData as any).permission || 'private',
            projectId: (moduleData as any).projectId || '',
            resourceId: (moduleData as any).resourceId || '',
            modelId: (moduleData as any).modelId || '',
            createdAt: (moduleData as any).createdAt || new Date().toISOString(),
            updatedAt: new Date().toISOString(),
          }
          modulesMap.set(moduleId, completeModuleData)
        }
        modules.value.set(activeDrawingId.value, modulesMap)
      }

      // 清空当前画布
      graphRef.value.clearCells()

      // 导入画布数据
      if (jsonData.canvasData.cells && jsonData.canvasData.cells.length > 0) {
        graphRef.value.fromJSON({ cells: jsonData.canvasData.cells })

        // 确保导入的边不显示箭头（未选中状态）
        removeAllEdgeArrows()

        // 应用画布属性
        if (jsonData.canvasProperties) {
          setTimeout(() => {
            updateBackgroundColor(backgroundColor.value)
            updateGridType(gridType.value)
            toggleNodeLabels(elementsStandard.value)
          }, 100)
        }
      }

      const moduleCount = Object.keys(jsonData.modules || {}).length
      const nodeCount = jsonData.statistics?.nodesCount || jsonData.canvasData.cellsCount || 0

      ElMessage.success(`成功导入 ${jsonData.name}，包含 ${nodeCount} 个元素${moduleCount > 0 ? `，${moduleCount} 个模块` : ''}`)

    } else if (isOldCompleteExport) {
      // 处理旧格式的完整导出数据
      console.log('检测到旧格式完整数据，正在导入...')

      // 1. 导入图纸信息
      if (jsonData.drawings && Array.isArray(jsonData.drawings)) {
        drawings.value = jsonData.drawings
        if (jsonData.activeDrawingId !== undefined) {
          activeDrawingId.value = jsonData.activeDrawingId
        }
      }

      // 2. 导入图纸属性
      if (jsonData.drawingProperties) {
        drawingProperties.value.clear()
        for (const [drawingId, props] of Object.entries(jsonData.drawingProperties)) {
          drawingProperties.value.set(Number(drawingId), props as any)
        }
      }

      // 3. 导入选择组数据
      if (jsonData.selectionGroups) {
        selectionGroups.value.clear()
        for (const [drawingId, groups] of Object.entries(jsonData.selectionGroups)) {
          const groupsMap = new Map()
          for (const [groupId, groupData] of Object.entries(groups as any)) {
            groupsMap.set(groupId, groupData)
          }
          selectionGroups.value.set(Number(drawingId), groupsMap)
        }
      }

      // 4. 导入模块数据
      if (jsonData.modules) {
        modules.value.clear()
        for (const [drawingId, moduleMap] of Object.entries(jsonData.modules)) {
          const modulesMap = new Map()
          for (const [moduleId, moduleData] of Object.entries(moduleMap as any)) {
            // 确保模块数据包含必要的字段
            const completeModuleData = Object.assign({}, moduleData, {
              cells: (moduleData as any).cells || [],
              name: (moduleData as any).name || `模块_${moduleId}`,
              description: (moduleData as any).description || '',
              type: (moduleData as any).type || '元件',
              category: (moduleData as any).category || '',
              permission: (moduleData as any).permission || 'private',
              projectId: (moduleData as any).projectId || '',
              resourceId: (moduleData as any).resourceId || '',
              modelId: (moduleData as any).modelId || '',
              createdAt: (moduleData as any).createdAt || new Date().toISOString(),
              updatedAt: (moduleData as any).updatedAt || new Date().toISOString(),
            })
            modulesMap.set(moduleId, completeModuleData)
          }
          modules.value.set(Number(drawingId), modulesMap)
        }
      }

      // 5. 导入画布数据（只导入cells）
      const canvasData = {
        cells: jsonData.cells || [],
      }

      // 清空当前画布
      graphRef.value.clearCells()

      // 导入画布数据
      if (canvasData.cells.length > 0) {
        graphRef.value.fromJSON(canvasData)

        // 恢复边的格式属性
        setTimeout(() => {
          restoreEdgeProperties()
        }, 100)

        // 确保导入的边不显示箭头（未选中状态）
        removeAllEdgeArrows()
      }

      const moduleCount = Object.keys(jsonData.modules || {}).reduce((total, drawingId) => {
        return total + Object.keys(jsonData.modules[drawingId] || {}).length
      }, 0)

      ElMessage.success(`成功导入旧格式完整数据，包含 ${moduleCount} 个模块`)
          } else {
      // 处理简单的画布数据导入（只有cells的JSON）
      console.log('检测到简单画布数据，正在导入...')

      // 清空当前画布
      graphRef.value.clearCells()

      // 导入JSON数据
      graphRef.value.fromJSON(jsonData)

      // 恢复边的格式属性
      setTimeout(() => {
        restoreEdgeProperties()
      }, 100)

      // 确保导入的边不显示箭头（未选中状态）
      removeAllEdgeArrows()

      ElMessage.success('JSON数据导入成功')
    }

    // 居中显示内容
    graphRef.value.centerContent()

    // 保存到当前图纸
    saveGraphContent()

    // 如果导入了模块数据，检查当前画布中是否有模块节点需要关联
    if ((isOldCompleteExport || isNewFormat) && jsonData.modules) {
      setTimeout(() => {
        linkModuleNodes()
      }, 100)
    }

    // 导入完成后，处理节点配置回显
    setTimeout(() => {
      restoreNodeConfigurations()
    }, 200)
  } catch (error) {
    console.error('执行导入操作失败:', error)
    ElMessage.error('导入数据失败，请检查数据格式')
  }
}

// 关联模块节点 - 将画布中的模块节点与模块数据关联
const linkModuleNodes = () => {
  if (!graphRef.value) return

  const currentDrawingModules = modules.value.get(activeDrawingId.value)
  if (!currentDrawingModules) return

  // 获取画布中所有节点
  const nodes = graphRef.value.getNodes()

  nodes.forEach((node) => {
    const nodeId = node.id

    // 检查这个节点是否是模块节点
    if (currentDrawingModules.has(nodeId)) {
      const moduleData = currentDrawingModules.get(nodeId)
      if (moduleData) {
        // 更新模块数据中的node引用
        moduleData.node = node

        // 确保节点有正确的模块标识
        node.setData({ isModule: true, moduleId: nodeId })

        // 更新节点样式以表明它是模块
        node.attr('body/stroke', '#FF6B35')
        node.attr('body/strokeWidth', 2)

        // console.log(`已关联模块节点: ${moduleData.name} (${nodeId})`)
      }
    }
  })
}

// 恢复节点配置 - 导入后处理节点配置数据回显
const restoreNodeConfigurations = () => {
  if (!graphRef.value) return

  try {
    // 获取画布中所有节点
    const nodes = graphRef.value.getNodes()

    nodes.forEach((node) => {
      const nodeData = node.getData() || {}

      // 检查是否为模块节点，如果是则需要特殊处理
      const drawingModulesMap = modules.value.get(activeDrawingId.value)
      if (drawingModulesMap && drawingModulesMap.has(node.id)) {
        // 是模块节点，确保模块名称和节点显示同步
        const moduleData = drawingModulesMap.get(node.id)
        if (moduleData && nodeData.properties?.name) {
          // 如果节点数据中有名称，同步到模块数据和节点显示
          moduleData.name = nodeData.properties.name
          node.attr('label/text', nodeData.properties.name)
          // console.log(`恢复模块节点 ${node.id} 的名称:`, nodeData.properties.name)
        } else if (moduleData) {
          // 如果模块数据有名称但节点数据没有，同步到节点
          node.attr('label/text', moduleData.name)
          node.setData({
            ...nodeData,
            name: moduleData.name,
            properties: {
              ...nodeData.properties,
              name: moduleData.name,
            },
          })
          // console.log(`从模块数据恢复节点 ${node.id} 的名称:`, moduleData.name)
        }
      }

      // 如果节点有配置数据，恢复引脚显示和其他配置
      if (nodeData.pins) {
        // 恢复引脚文本显示
        Object.entries(nodeData.pins).forEach(([pinId, value]) => {
          if (value && typeof value === 'string' && value.trim() !== '') {
            updatePortText(node, pinId, value)
          }
        })
      }

      // 如果节点有自定义属性，确保它们被正确设置
      if (nodeData.properties) {
        // 这里可以根据需要处理特定的属性恢复逻辑
        Object.entries(nodeData.properties).forEach(([key, value]) => {
          // 对于非模块节点，处理名称属性
          if (key === 'name' && !drawingModulesMap?.has(node.id) && typeof value === 'string') {
            node.attr('label/text', value)
          }
          // console.log(`恢复节点 ${node.id} 的属性 ${key}:`, value)
        })
      }
    })

    // 如果有选中的节点，重新触发配置更新
    if (selectedNode.value && selectedNode.value.isNode?.()) {
      updateNodeConfiguration(selectedNode.value as Node)
    }

    // console.log('节点配置恢复完成')
  } catch (error) {
    console.error('恢复节点配置时出错:', error)
  }
}

// 关闭对话框时重置状态
const handleDialogClose = () => {
  selectedFileName.value = ''
  if (fileInputRef.value) {
    fileInputRef.value.value = ''
  }
}

// 添加importSelected函数
const importSelected = () => {
  if (!selectedFileName.value || !fileInputRef.value) return
  handleFileSelect({ target: fileInputRef.value } as any)
}

// 添加气泡框显示状态
const showTooltipBubble = ref(false)
const tooltipContent = ref('没有问题，使用 Ctrl + M 启动检查')

// 显示气泡框
const showBubble = () => {
  showTooltipBubble.value = true
  // 3秒后自动隐藏
  setTimeout(() => {
    showTooltipBubble.value = false
  }, 3000)
}

// 运行功能相关状态
const websocketDialogVisible = ref(false)
const websocketThreadsData = ref([
  { id: 0, type: 'Node', info: 'component (newGraph) will be chosen as loop node with initial value 0', active: true },
  { id: 1, type: 'Node', info: 'component (newGraph) will be chosen as loop node with initial value 0', active: true },
  { id: 2, type: 'Node', info: 'component (newGraph) will be chosen as loop node with initial value 0', active: true },
  { id: 3, type: 'Node', info: 'component (newGraph) will be chosen as loop node with initial value 0', active: true },
  { id: 4, type: 'Node', info: 'component (newGraph) will be chosen as loop node with initial value 0', active: true },
])
const websocketSystemInfo = ref({
  electricalNodes: 10,
  controlNodes: 69,
  runTime: new Date().toLocaleString(),
})
const websocketChartData = ref({
  voltageData: [] as number[],
  phaseData: [] as number[],
  timeData: [] as number[],
})
const websocketCompleted = ref(false)
let websocketInterval: any = null

// 显示WebSocket监控对话框
const showWebsocketDialog = () => {
  websocketDialogVisible.value = true

  // Reset completion status
  websocketCompleted.value = false

  // Generate initial chart data
  generateWebsocketChartData()

  // Start streaming data
  startWebsocketSimulation()
}

// Generate initial chart data for WebSocket
const generateWebsocketChartData = () => {
  const voltageData: number[] = []
  const phaseData: number[] = []
  const timeData: number[] = []

  for (let i = 0; i < 300; i++) {
    const time = i * 0.01
    timeData.push(time)

    if (i < 50) {
      voltageData.push(180 + Math.random() * 20)
    } else if (i < 150) {
      voltageData.push(80 + Math.random() * 20)
    } else if (i < 200) {
      voltageData.push(140 + Math.random() * 20)
    } else {
      voltageData.push(90 + Math.random() * 20)
    }

    phaseData.push(150 * Math.sin(10 * time))
  }

  websocketChartData.value = {
    voltageData,
    phaseData,
    timeData,
  }
}

// Start WebSocket simulation
const startWebsocketSimulation = () => {
  // Clear any existing interval
  if (websocketInterval !== null) {
    globalThis.clearInterval(websocketInterval)
  }

  // Update data with a longer interval for better sequential display
  websocketInterval = globalThis.setInterval(() => {
    // Update thread status randomly
    const randomIndex = Math.floor(Math.random() * websocketThreadsData.value.length)
    const updatedThreads = [...websocketThreadsData.value]
    updatedThreads[randomIndex] = {
      ...updatedThreads[randomIndex],
      active: !updatedThreads[randomIndex].active,
    }
    websocketThreadsData.value = updatedThreads

    // Update system info
    websocketSystemInfo.value = {
      ...websocketSystemInfo.value,
      runTime: new Date().toLocaleString(),
    }

    // Update chart data
    updateWebsocketChartData()

    // Mark as completed after some time
    setTimeout(() => {
      websocketCompleted.value = true
    }, 15000)
  }, 800) // Increased delay for better visual effect
}

// Update chart data to simulate streaming
const updateWebsocketChartData = () => {
  // Make a new copy of the data
  const voltageData = [...websocketChartData.value.voltageData]
  const phaseData = [...websocketChartData.value.phaseData]
  const timeData = [...websocketChartData.value.timeData]

  // Add a new data point
  const lastTime = timeData.length > 0 ? timeData.at(-1) : 0
  const newTime = (lastTime || 0) + 0.01
  timeData.push(newTime)

  // Generate voltage based on time pattern
  if (newTime % 3 < 0.5) {
    voltageData.push(180 + Math.random() * 20)
  } else if (newTime % 3 < 1.5) {
    voltageData.push(80 + Math.random() * 20)
  } else if (newTime % 3 < 2) {
    voltageData.push(140 + Math.random() * 20)
  } else {
    voltageData.push(90 + Math.random() * 20)
  }

  // Generate phase data
  phaseData.push(150 * Math.sin(10 * newTime))

  // Keep data size manageable
  if (timeData.length > 300) {
    timeData.shift()
    voltageData.shift()
    phaseData.shift()
  }

  // Update chart data
  websocketChartData.value = {
    voltageData,
    phaseData,
    timeData,
  }
}

// Clean up on WebSocket dialog close
const handleWebsocketDialogClose = () => {
  if (websocketInterval !== null) {
    globalThis.clearInterval(websocketInterval)
    websocketInterval = null
  }
}

// 处理文件拖拽事件
const handleDragOver = (e: DragEvent) => {
  e.preventDefault()
  isDraggingFile.value = true
}

const handleDragLeave = (e: DragEvent) => {
  e.preventDefault()
  isDraggingFile.value = false
}

// 处理节点属性变化
const handlePropertyChange = (data: { key: string; value: any }) => {
  if (selectedNode.value) {
    const { key, value } = data
    const currentData = selectedNode.value.getData() || {}

    // 检查是否为模块节点
    const drawingModulesMap = modules.value.get(activeDrawingId.value)
    if (drawingModulesMap && drawingModulesMap.has(selectedNode.value.id)) {
      // 是模块节点，更新模块数据
      const moduleData = drawingModulesMap.get(selectedNode.value.id)
      if (moduleData && key === 'name') {
        moduleData.name = value
        // 更新节点显示
        selectedNode.value.attr('label/text', value)
        // 更新节点数据
        selectedNode.value.setData({
          ...currentData,
          name: value,
          properties: {
            ...currentData.properties,
            name: value,
          },
        })
        // 保存图纸内容
        saveGraphContent()
        return
      }
    }

    // 非模块节点的原有处理逻辑
    const propertyValues = currentData.propertyValues || {}
    propertyValues[key] = value

    // 同时保存到properties结构中
    const properties = currentData.properties || {}
    properties[key] = value

    selectedNode.value.setData({
      ...currentData,
      propertyValues,
      properties,
    })

    // 根据属性类型应用到节点外观
    switch (key) {
      case 'name': {
        selectedNode.value.attr('label/text', value)
        break
      }
      case 'fillColor': {
        selectedNode.value.attr('body/fill', value)
        break
      }
      case 'enabled': {
        // 当启用状态变化时，更新节点透明度
        const opacity = value ? 1 : 0.5
        selectedNode.value.attr('body/opacity', opacity)
        // 如果节点有图片，也更新图片透明度
        if (selectedNode.value.attr('image')) {
          selectedNode.value.attr('image/opacity', opacity)
        }
        // 更新文本透明度
        if (selectedNode.value.attr('label')) {
          selectedNode.value.attr('label/opacity', opacity)
        }
        break
      }
    }

    // 检查是否需要更新SVG文本（优先使用JSON配置）
    updateSVGNodeText(selectedNode.value as Node, key, value)

    nodePropertiesData.value = {
      ...nodePropertiesData.value,
      propertyValues,
      properties,
    }
  }
}

const updateSVGNodeText = async (node: Node, propertyKey: string, value: any) => {
  try {
    if (!node || !graphRef.value) return

    // 优先使用JSON配置的节点注册数据
    if (nodeRegistrationsFromJSON.value && nodeRegistrationsFromJSON.value.length > 0) {
      // 调用JSON配置驱动的SVG文本更新
      await updateSVGTextContentFromJSON(node, propertyKey, value)
      return
    }

    // 回退到原有的硬编码方式（保持向后兼容）
    const nodeConfig = getNodeConfiguration(node.shape as string)
    if (!nodeConfig) return

    const property = nodeConfig.properties.find((p) => p.key === propertyKey && p.svgTextTarget)
    if (!property || !property.svgTextSelector || !property.svgTextFormat) return

    const formattedText = property.svgTextFormat(value)

    const nodeView = graphRef.value ? node.findView(graphRef.value as any) : null
    if (!nodeView) return

    const imageElement = nodeView.container.querySelector('image')
    if (!imageElement) return

    const svgHref = imageElement.getAttribute('href') || imageElement.getAttribute('xlink:href')
    if (!svgHref || (typeof svgHref === 'string' && svgHref.startsWith('blob:'))) {
      // 尝试从节点数据中获取原始SVG路径，如果没有则跳过更新
      const nodeData = node.getData() || {}
      const originalSvgPath = nodeData.originalSvgPath
      if (!originalSvgPath) {
        console.warn('无法获取原始SVG路径，跳过文本更新:', node.shape)
        return
      }
      await updateSvgFromPath(node, originalSvgPath, property.svgTextSelector!, formattedText)
      return
    }

    await updateSvgFromPath(node, svgHref, property.svgTextSelector!, formattedText)
  } catch (error) {
    console.error('更新SVG节点文本时出错:', error)
  }
}

// 基于JSON配置的SVG文本更新函数
const updateSVGTextContentFromJSON = async (node: Node, propertyKey: string, value: any) => {
  try {
    // 导入nodeInfo模块
    const nodeInfoModule = await import('./utils/nodeInfo')
    const { getNodeConfigurationFromJSON } = nodeInfoModule

    // 获取节点配置
    const nodeConfig = getNodeConfigurationFromJSON(node.shape as string, nodeRegistrationsFromJSON.value)
    if (!nodeConfig) {
      console.log('未找到节点配置:', node.shape)
      return
    }

    // 查找具有svgTextTarget标识的属性
    const property = nodeConfig.properties.find((p) => p.key === propertyKey && p.svgTextTarget)
    if (!property || !property.svgTextSelector) {
      // console.log('属性未配置SVG文本更新:', propertyKey)
      return
    }

    // 格式化文本内容
    let formattedText = value
    if (property.svgTextFormat && typeof property.svgTextFormat === 'string') {
      try {
        // 执行文本格式化表达式
        // 处理箭头函数格式的表达式 "value => `${value}Ω`"
        const formatExpression = property.svgTextFormat.trim()
        // console.log('SVG文本格式化表达式:', formatExpression)

        if (formatExpression.includes('=>')) {
          // 箭头函数格式：value => `${value}Ω`
          const formatFunc = new Function('value', `return (${formatExpression})(value)`)
          formattedText = formatFunc(value)
        } else {
          // 直接表达式格式
          const formatFunc = new Function('value', `return ${formatExpression}`)
          formattedText = formatFunc(value)
        }

        // console.log('SVG文本格式化结果:', { original: value, formatted: formattedText })
      } catch {
        // console.error('SVG文本格式化失败:', error, '表达式:', property.svgTextFormat)
        // 如果格式化失败，使用原始值作为回退
        formattedText = String(value)
      }
    }

    // 获取节点的DOM元素
    const nodeView = graphRef.value ? node.findView(graphRef.value as any) : null
    if (!nodeView) return

    // 查找SVG中的image元素
    const imageElement = nodeView.container.querySelector('image')
    if (!imageElement) return

    // 获取SVG的href
    const svgHref = imageElement.getAttribute('href') || imageElement.getAttribute('xlink:href')
    if (!svgHref) return

    // 处理blob URL或原始SVG路径
    let svgPath = svgHref
    if (typeof svgHref === 'string' && svgHref.startsWith('blob:')) {
      // 如果是blob URL，尝试从节点配置中获取原始SVG路径
      const originalSvgPath = nodeConfig.shape.attrs?.image?.['xlink:href']
      if (!originalSvgPath) {
        // console.error('无法获取节点的原始SVG路径:', node.shape)
        return
      }
      svgPath = originalSvgPath
    }

    // 更新SVG文本
    await updateSvgFromPath(node, svgPath, property.svgTextSelector, formattedText)

    // console.log(`已通过JSON配置更新SVG文本: ${propertyKey} = ${formattedText}`)

    // 保存更新后的属性值到节点数据中
    const nodeData = node.getData() || {}
    const properties = nodeData.properties || {}
    properties[propertyKey] = value
    node.setData({ ...nodeData, properties })
  } catch (error) {
    console.error('基于JSON配置更新SVG文本时出错:', error)
  }
}

// 初始化节点的SVG文本（应用默认值）
const initializeNodeSVGText = async (node: Node) => {
  try {
    if (!nodeRegistrationsFromJSON.value || nodeRegistrationsFromJSON.value.length === 0) return

    const nodeInfoModule = await import('./utils/nodeInfo')
    const { getNodeConfigurationFromJSON } = nodeInfoModule

    // 获取节点配置
    const nodeConfig = getNodeConfigurationFromJSON(node.shape as string, nodeRegistrationsFromJSON.value)
    if (!nodeConfig) return

    // 查找所有配置了SVG文本更新的属性
    const svgTextProperties = nodeConfig.properties.filter((p) => p.svgTextTarget && p.svgTextSelector)

    for (const property of svgTextProperties) {
      // 使用默认值初始化SVG文本
      const defaultValue = property.defaultValue
      if (defaultValue !== undefined && defaultValue !== null) {
        await updateSVGTextContentFromJSON(node, property.key, defaultValue)
        // console.log(`初始化节点SVG文本: ${property.key} = ${defaultValue}`)
      }
    }
  } catch {
    // console.error('初始化节点SVG文本时出错:', error)
  }
}

// 从SVG路径更新文本的辅助函数
const updateSvgFromPath = async (node: Node, svgPath: string, textSelector: string, newText: string) => {
  try {
    const response = await fetch(svgPath)
    const svgContent = await response.text()

    // 解析SVG并更新文本
    const parser = new DOMParser()
    const svgDoc = parser.parseFromString(svgContent, 'image/svg+xml')
    const textElements = svgDoc.querySelectorAll(textSelector)

    if (textElements.length > 0) {
      // 更新第一个匹配的text元素
      textElements[0].textContent = newText

      // 转换回SVG字符串
      const serializer = new XMLSerializer()
      const updatedSvgContent = serializer.serializeToString(svgDoc)

      // 创建blob URL
      const blob = new Blob([updatedSvgContent], { type: 'image/svg+xml' })
      const newSvgUrl = URL.createObjectURL(blob)

      // 清理旧的blob URL
      const oldHref = node.attr('image/xlink:href') as string
      if (oldHref && typeof oldHref === 'string' && oldHref.startsWith('blob:')) {
        URL.revokeObjectURL(oldHref)
      }

      // 更新节点的image src
      node.setAttrByPath('image/xlink:href', newSvgUrl)

      // 将更新的SVG URL保存到节点数据中，用于持久化
      const nodeData = node.getData() || {}
      nodeData.customSvgUrl = newSvgUrl
      node.setData(nodeData)
    }
  } catch (error) {
    console.error('从SVG路径更新文本时出错:', error)
  }
}

// 处理节点参数变化
const handleParameterChange = (data: { group: string; key: string; value: any }) => {
  if (selectedNode.value) {
    const { group, key, value } = data
    const currentData = selectedNode.value.getData() || {}
    const parameterValues = currentData.parameterValues || {}
    const parameterGroups = currentData.parameterGroups || {}

    // 根据组织结构存储参数值
    if (group === 'dynamic') {
      // 处理动态参数，key格式为 "panelKey.paramKey"
      const [panelKey, paramKey] = key.split('.')
      if (!parameterValues[panelKey]) {
        parameterValues[panelKey] = {}
      }
      parameterValues[panelKey][paramKey] = value

      // 同时保存到parameterGroups结构中
      if (!parameterGroups[panelKey]) {
        parameterGroups[panelKey] = {}
      }
      parameterGroups[panelKey][paramKey] = value
    } else {
      // 处理标准参数组
      if (!parameterValues[group]) {
        parameterValues[group] = {}
      }
      parameterValues[group][key] = value

      // 同时保存到parameterGroups结构中
      if (!parameterGroups[group]) {
        parameterGroups[group] = {}
      }
      parameterGroups[group][key] = value
    }

    selectedNode.value.setData({
      ...currentData,
      parameterValues,
      parameterGroups,
    })

    // 根据参数类型应用到节点外观或行为
    switch (key) {
      case 'fillColor': {
        selectedNode.value.attr('body/fill', value)
        break
      }
      case 'name': {
        selectedNode.value.attr('label/text', value)
        break
      }
      // 可以根据需要添加更多参数的处理逻辑
    }

    // 检查是否需要更新SVG文本
    updateSVGNodeText(selectedNode.value as Node, key, value)

    nodePropertiesData.value = {
      ...nodePropertiesData.value,
      parameterValues,
      parameterGroups,
    }

    console.log('已更新节点参数:', { group, key, value })
  }
}

// 更新链接桩文本显示
const updatePortText = (node: Node, pinId: string, value: string) => {
  try {
    if (!graphRef.value) return

    // 移除已存在的文本标签
    removePortText(node, pinId)

    // 如果值为空，不显示文本
    if (!value || value.trim() === '') return

    // 使用AntV X6的文本标签功能
    const ports = node.getPorts()
    const port = ports.find((p) => p.id === pinId)
    if (!port) return

    // 获取文本对齐方式
    const textAnchor = getTextAnchor(node, pinId)

    // 获取端口组类型，确定标签位置
    const portGroup = node.getPortProp(pinId, 'group') || 'right'

    // 更新端口属性以显示文本
    node.setPortProp(pinId, 'attrs/text', {
      text: value,
      fill: '#000000', // 改为黑色，与节点边框颜色一致
      fontSize: 12,
      fontWeight: 'bold',
      textAnchor,
      // 设置文本位置偏移，使其显示在连接桩和transform框外侧
      // refX: getTextOffsetX(node, pinId),
      // refY: getTextOffsetY(node, pinId),
      pointerEvents: 'none',
      // 添加文本背景以提高可读性
      stroke: 'white',
      strokeWidth: 3,
      paintOrder: 'stroke',
    })

  } catch (error) {
    console.error('更新端口文本时出错:', error)
  }
}

// // 获取文本X轴偏移
// const getTextOffsetX = (node: Node, pinId: string): number => {
//   const portGroup = node.getPortProp(pinId, 'group') || 'right'
//   const portData = (node.getPortProp(pinId, 'args') || {}) as { x?: number; y?: number }
//   const nodeSize = node.getSize()

//   // 增加基础偏移量，确保文本在连接桩和transform框外侧
//   const baseOffset = Math.max(nodeSize.width, 200) // 增大偏移量，确保在transform框外侧

//   switch (portGroup) {
//     case 'left': {
//       // 左侧端口：文本显示在节点左边界外侧
//       return -(nodeSize.width / 2 + baseOffset)
//     }
//     case 'right': {
//       // 右侧端口：文本显示在节点右边界外侧
//       return 500
//     }
//     case 'top':
//     case 'bottom': {
//       // 上下端口：文本水平居中显示
//       return 0
//     }
//     case 'customPorts': {
//       if (portData.x !== undefined) {
//         const relativeX = portData.x / nodeSize.width
//         const centerX = nodeSize.width / 2

//         if (relativeX < 0.3) {
//           // 左侧：确保文本在节点外侧
//           return -(centerX + baseOffset)
//         } else if (relativeX > 0.7) {
//           // 右侧：确保文本在节点外侧
//           return centerX + baseOffset
//         } else {
//           // 中间位置：水平居中
//           return 0
//         }
//       }
//       // 默认右侧
//       return nodeSize.width / 2 + baseOffset
//     }
//     default: {
//       return nodeSize.width / 2 + baseOffset
//     }
//   }
// }

// // 获取文本Y轴偏移
// const getTextOffsetY = (node: Node, pinId: string): number => {
//   const portGroup = node.getPortProp(pinId, 'group') || 'right'
//   const portData = (node.getPortProp(pinId, 'args') || {}) as { x?: number; y?: number }
//   const nodeSize = node.getSize()

//   // 增加基础垂直偏移量，确保文本在连接桩和transform框外侧清晰显示
//   const baseVerticalOffset = Math.max(nodeSize.height * 0.25, 40) // 增大垂直偏移量

//   switch (portGroup) {
//     case 'left':
//     case 'right': {
//       // 左右端口：文本垂直居中对齐连接桩位置
//       return 0
//     }
//     case 'top': {
//       // 顶部端口：文本显示在节点上方外侧
//       return -(nodeSize.height / 2 + baseVerticalOffset)
//     }
//     case 'bottom': {
//       // 底部端口：文本显示在节点下方外侧
//       return nodeSize.height / 2 + baseVerticalOffset
//     }
//     case 'customPorts': {
//       if (portData.y !== undefined) {
//         const relativeY = portData.y / nodeSize.height
//         const centerY = nodeSize.height / 2

//         if (relativeY < 0.3) {
//           // 顶部：确保文本在节点外侧
//           return -(centerY + baseVerticalOffset)
//         } else if (relativeY > 0.7) {
//           // 底部：确保文本在节点外侧
//           return centerY + 200
//         } else {
//           // 中间位置：垂直居中对齐连接桩
//           return 0
//         }
//       }
//       return 0
//     }
//     default: {
//       return 0
//     }
//   }
// }

// 获取文本对齐方式
const getTextAnchor = (node: Node, pinId: string): string => {
  const portGroup = node.getPortProp(pinId, 'group') || 'right'
  const portData = (node.getPortProp(pinId, 'args') || {}) as { x?: number; y?: number }
  const nodeSize = node.getSize()

  switch (portGroup) {
    case 'left': {
      // 左侧端口：文本右对齐（文本在端口左侧）
      return 'end'
    }
    case 'right': {
      // 右侧端口：文本左对齐（文本在端口右侧）
      return 'start'
    }
    case 'top':
    case 'bottom': {
      // 上下端口：文本居中对齐
      return 'middle'
    }
    case 'customPorts': {
      if (portData.x !== undefined) {
        const relativeX = portData.x / nodeSize.width

        if (relativeX < 0.3) {
          // 左侧：文本右对齐
          return 'end'
        } else if (relativeX > 0.7) {
          // 右侧：文本左对齐
          return 'start'
        } else {
          // 中间：文本居中对齐
          return 'middle'
        }
      }
      // 默认左对齐（右侧端口）
      return 'start'
    }
    default: {
      return 'start'
    }
  }
}

// 移除链接桩文本
const removePortText = (node: Node, pinId: string) => {
  try {
    // 清除端口文本属性
    node.removePortProp(pinId, 'attrs/text')
  } catch (error) {
    console.error('移除端口文本时出错:', error)
  }
}

// 处理引脚值变化
const handlePinValueChange = (data: { pinId: string; type: string; value: any }) => {
  if (selectedNode.value) {
    const { pinId, value } = data
    const currentData = selectedNode.value.getData() || {}
    const pins = currentData.pins || {}
    pins[pinId] = value

    selectedNode.value.setData({
      ...currentData,
      pins,
    })

    // 更新链接桩上的文本显示
    if (selectedNode.value) {
      updatePortText(selectedNode.value as Node, pinId, value)
    }

    nodePropertiesData.value = {
      ...nodePropertiesData.value,
      pins,
    }

  }
}

// 应用更改
const handleApplyChanges = () => {
  // 保存图纸内容
  saveGraphContent()
}

// 更新节点配置信息
const updateNodeConfiguration = (node: Node) => {
  // 检查是否为模块节点
  const drawingModulesMap = modules.value.get(activeDrawingId.value)
  if (drawingModulesMap && drawingModulesMap.has(node.id)) {
    // 是模块节点，使用模块的配置
    const moduleData = drawingModulesMap.get(node.id)
    if (moduleData) {
      // 获取节点当前的显示名称，优先级：节点属性 > 模块数据 > 节点标签
      const nodeData = node.getData() || {}
      const currentName = nodeData.properties?.name || nodeData.name || moduleData.name || node.attr('label/text') || '未命名模块'

      currentNodeConfiguration.value = {
        nodeType: 'module',
        name: currentName,
        category: '模块',
        properties: [
          {
            key: 'name',
            label: '模块名称',
            type: 'input',
            defaultValue: currentName,
            placeholder: '请输入模块名称',
            required: true,
          },
          {
            key: 'enabled',
            label: '启用',
            type: 'switch',
            defaultValue: true,
          },
        ],
        pins: [],
      }

      // 更新节点属性数据，确保名称的一致性
      nodePropertiesData.value = {
        id: node.id,
        shape: node.shape,
        x: node.getPosition().x,
        y: node.getPosition().y,
        width: node.getSize().width,
        height: node.getSize().height,
        name: currentName,
        properties: {
          name: currentName,
          enabled: nodeData.properties?.enabled ?? true,
          ...nodeData.properties,
        },
        // 保留其他现有数据
        ...nodeData,
      }
      return
    }
  }

  // 非模块节点的原有处理逻辑
  let nodeConfig = getNodeConfiguration(node.shape as string)

  // 如果没有找到配置，创建一个基本配置
  if (!nodeConfig) {
    nodeConfig = {
      nodeType: node.shape as string,
      name: node.shape as string,
      category: '基础形状',
      properties: [
        {
          key: 'name',
          label: '节点名称',
          type: 'input',
          defaultValue: '',
          placeholder: '请输入节点名称',
          required: true,
        },
        {
          key: 'enabled',
          label: '启用',
          type: 'switch',
          defaultValue: true,
        },
      ],
      pins: [],
    }
  }

  // 动态生成引脚配置基于节点的实际连接桩
  const dynamicPins: NodePin[] = []

  // 检查节点是否有ports配置
  const ports = node.getPorts()
  if (ports && ports.length > 0) {
    // 基于实际的ports生成引脚配置
    ports.forEach((port, index) => {
      const portId = port.id || `port_${index}`
      const portData = node.getPortProp(portId, 'args') || {}
      const position = node.getPortProp(portId, 'group') || 'right'

      // 获取端口的文本内容，如果有的话
      const textAttr =
        node.getPortProp(portId, 'attrs/text/text') || node.attr(`ports/${portId}/attrs/text/text`) || (portData as any).text || portId

      dynamicPins.push({
        id: portId,
        label: `引脚${index + 1}`,
        position: position as 'left' | 'right' | 'top' | 'bottom',
        type: position === 'left' || position === 'top' ? 'input' : 'output',
        defaultValue: String(textAttr || ''),
      })
    })
  } else {
    // 如果节点没有ports，检查是否有通用的连接桩属性
    // const nodeAttrs = node.getAttrs()
    // let portCount = 0

    // 根据节点形状和属性推断连接桩
    const nodeShape = node.shape
    switch (nodeShape) {
      case 'rect':
      case 'circle':
      case 'ellipse': {
        // 默认创建左右两个连接桩
        dynamicPins.push(
          {
            id: 'port_left',
            label: '左侧引脚',
            position: 'left',
            type: 'input',
            defaultValue: '44',
          },
          {
            id: 'port_right',
            label: '右侧引脚',
            position: 'right',
            type: 'output',
            defaultValue: '666',
          }
        )
        break
      }
      case 'polygon': {
        // 多边形节点创建四个连接桩
        dynamicPins.push(
          {
            id: 'port_left',
            label: '左侧引脚',
            position: 'left',
            type: 'input',
            defaultValue: 'L',
          },
          {
            id: 'port_top',
            label: '顶部引脚',
            position: 'top',
            type: 'input',
            defaultValue: 'T',
          },
          {
            id: 'port_right',
            label: '右侧引脚',
            position: 'right',
            type: 'output',
            defaultValue: 'R',
          },
          {
            id: 'port_bottom',
            label: '底部引脚',
            position: 'bottom',
            type: 'output',
            defaultValue: 'B',
          }
        )
        break
      }
      default: {
        // 其他节点类型默认两个连接桩
        dynamicPins.push(
          {
            id: 'port_input',
            label: '输入引脚',
            position: 'left',
            type: 'input',
            defaultValue: 'IN',
          },
          {
            id: 'port_output',
            label: '输出引脚',
            position: 'right',
            type: 'output',
            defaultValue: 'OUT',
          }
        )
        break
      }
    }
  }

  // 如果动态生成的引脚数量大于0，使用动态引脚；否则使用配置中的引脚
  if (dynamicPins.length > 0) {
    nodeConfig.pins = dynamicPins
  }

  currentNodeConfiguration.value = nodeConfig

  // 更新节点属性数据，从节点的data属性中获取
  const nodeData = node.getData() || {}

  // 获取节点名称，优先级：节点数据中的名称 > 节点标签文本 > 默认值
  const nodeName =
    nodeData.properties?.name ||
    nodeData.name ||
    node.attr('label/text') ||
    nodeConfig.properties.find((p) => p.key === 'name')?.defaultValue ||
    ''

  // 合并现有数据和默认值，优先使用已存在的数据
  const mergedPinsData = nodeConfig.pins.reduce(
    (acc, pin) => {
      // 优先使用节点已存在的引脚数据，如果没有则使用默认值
      acc[pin.id] = (nodeData.pins && nodeData.pins[pin.id]) || pin.defaultValue || ''
      return acc
    },
    {} as Record<string, string>
  )

  nodePropertiesData.value = {
    // 首先使用节点的现有数据
    ...nodeData,
    // 然后添加基本属性（可能会覆盖部分现有数据）
    id: node.id,
    shape: node.shape,
    x: node.getPosition().x,
    y: node.getPosition().y,
    width: node.getSize().width,
    height: node.getSize().height,
    name: nodeName,
    // 使用合并后的引脚数据
    pins: mergedPinsData,
    // 如果节点有自定义属性数据，确保保留并合并名称
    properties: {
      name: nodeName,
      ...nodeData.properties,
    },
    // 如果节点有参数组数据，确保保留
    parameterGroups: nodeData.parameterGroups || {},
  }

  // 显示所有引脚的当前值
  displayAllPinValues(node)
}

// 显示节点所有引脚的值
const displayAllPinValues = (node: Node) => {
  try {
    const nodeData = node.getData() || {}
    const pins = nodeData.pins || {}

    // 显示每个引脚的值
    Object.entries(pins).forEach(([pinId, value]) => {
      if (value && typeof value === 'string' && value.trim() !== '') {
        updatePortText(node, pinId, value)
      }
    })
  } catch (error) {
    console.error('显示引脚值时出错:', error)
  }
}

// 测试气泡功能已移除

// 气泡提示功能已就绪
</script>

<template>
  <div class="antvX6Demo-container">
    <div id="container" class="container-style">
      <left-side-panel
        :collapsed="leftSidebarCollapsed"
        :drawings="drawings"
        @create-drawing="createNewDrawing"
        @switch-drawing="switchToDrawing"
        @drawing-context-menu="showDrawingContextMenu"
      />
      <div class="context-center" :class="{ 'left-collapsed': leftSidebarCollapsed, 'right-collapsed': rightSidebarCollapsed }">
        <div class="center-header">
          <div class="toggle-sidebar left" @click="toggleLeftSidebar">
            <el-icon>
              <fold v-if="!leftSidebarCollapsed" />
              <expand v-else />
            </el-icon>
          </div>
          <div class="header-tabs">
            <div
              v-for="drawing in drawings"
              :key="drawing.id"
              class="header-tab"
              :class="{ active: drawing.active }"
              @click="switchToDrawing(drawing.id)"
            >
              <span>{{ drawing.name }}</span>
              <el-icon v-if="drawing.canDelete" class="close-icon" @click.stop="closeDrawing(drawing.id)"><close /></el-icon>
            </div>
            <!-- Add New Drawing Button -->
            <div class="header-tab add-tab" @click="createNewDrawing">
              <el-icon><plus /></el-icon>
            </div>
          </div>
          <!-- 导入JSON按钮 -->
          <div class="header-actions">
            <el-tooltip content="导入JSON数据" placement="bottom">
              <el-button class="import-btn" size="small" @click="showImportDialog">
                <el-icon><upload /></el-icon>
              </el-button>
            </el-tooltip>
          </div>
          <div class="toggle-sidebar right" @click="toggleRightSidebar">
            <el-icon>
              <fold v-if="!rightSidebarCollapsed" />
              <expand v-else />
            </el-icon>
          </div>
        </div>
        <div class="center-content">
          <div id="graph-container">
            <div class="zoom-indicator" :class="{ 'zoom-active': currentZoom !== 100 }">{{ currentZoom }}%</div>
          </div>
        </div>
      </div>
      <right-side-panel
        :collapsed="rightSidebarCollapsed"
        :active-tab="activeTab"
        :is-node-selected="isNodeSelected"
        :is-edge-selected="isEdgeSelected"
        :is-multiple-nodes-selected="isMultipleNodesSelected"
        :selected-node="selectedNode"
        :selected-edge="selectedEdge"
        :current-node-configuration="currentNodeConfiguration"
        :node-properties-data="nodePropertiesData"
        :background-color="backgroundColor"
        :grid-type="gridType"
        :grid-color="gridColor"
        :reference-standards-visible="referenceStandardsVisible"
        :elements-standard="elementsStandard"
        :guideline-standard="guidelineStandard"
        :grid-type-options="gridTypeOptions"
        :selection-groups="selectionGroups"
        :active-drawing-id="activeDrawingId"
        :active-selection-group="activeSelectionGroup"
        :is-editing-group="isEditingGroup"
        :group-background-color="groupBackgroundColor"
        :group-text="groupText"
        :is-selection-groups-collapsed="isSelectionGroupsCollapsed"
        :node-x="nodeX"
        :node-y="nodeY"
        :node-width="nodeWidth"
        :node-height="nodeHeight"
        :node-border-width="nodeBorderWidth"
        :node-font-size="nodeFontSize"
        :node-font-family="nodeFontFamily"
        :node-fill-color="nodeFillColor"
        :node-stroke-color="nodeStrokeColor"
        :node-label-color="nodeLabelColor"
        :edge-source-port="edgeSourcePort"
        :edge-target-port="edgeTargetPort"
        :edge-router-type="edgeRouterType"
        :edge-connector-type="edgeConnectorType"
        :edge-stroke-color="edgeStrokeColor"
        :edge-stroke-width="edgeStrokeWidth"
        :edge-fill-color="edgeFillColor"
        :edge-text-color="edgeTextColor"
        :edge-font-family="edgeFontFamily"
        :edge-font-size="edgeFontSize"
        :available-input-ports="availableInputPorts"
        :available-output-ports="availableOutputPorts"
        :router-type-options="routerTypeOptions"
        :connector-type-options="connectorTypeOptions"
        :font-options="fontOptions"
        @active-tab-change="handleActiveTabChange"
        @background-color-change="updateBackgroundColor"
        @grid-type-change="updateGridType"
        @grid-color-change="updateGridColor"
        @reference-standards-change="toggleReferenceStandards"
        @elements-standard-change="handleElementsStandardChange"
        @guideline-standard-change="handleGuidelineStandardChange"
        @toggle-selection-groups-collapse="toggleSelectionGroupsCollapse"
        @select-group-only="selectGroupOnly"
        @selection-group-context-menu="showSelectionGroupContextMenu"
        @edit-group="editGroup"
        @create-selection-group="createSelectionGroup"
        @back-to-groups-list="backToGroupsList"
        @update-selection-group="updateSelectionGroup"
        @delete-selection-group="deleteSelectionGroup"
              @apply-changes="handleApplyChanges"
              @parameter-change="handleParameterChange"
              @pin-value-change="handlePinValueChange"
              @property-change="handlePropertyChange"
        @node-position-change="updateNodePosition"
        @node-size-change="updateNodeSize"
        @reset-node-size="resetNodeSize"
        @bring-to-front="bringToFront"
        @send-to-back="sendToBack"
        @rotate-node="rotateNode"
        @node-fill-change="updateNodeFill"
        @node-stroke-change="updateNodeStroke"
        @node-stroke-width-change="updateNodeStrokeWidth"
        @node-label-color-change="updateNodeLabelColor"
        @node-font-size-change="updateNodeFontSize"
        @node-font-family-change="updateNodeFontFamily"
        @edge-source-port-change="updateEdgeSourcePort"
        @edge-target-port-change="updateEdgeTargetPort"
        @edge-router-type-change="updateEdgeRouterType"
        @edge-connector-type-change="updateEdgeConnectorType"
        @edge-stroke-color-change="updateEdgeStrokeColor"
        @edge-stroke-width-change="updateEdgeStrokeWidth"
        @edge-fill-color-change="updateEdgeFillColor"
        @edge-text-color-change="updateEdgeTextColor"
        @edge-font-family-change="updateEdgeFontFamily"
        @edge-font-size-change="updateEdgeFontSize"
      />
      <div class="context-foot">
        <div class="foot-content">
          <div class="foot-left">
            <div class="foot-button" @click="showBubble">
              <vab-icon icon="error-warning-line" />
              <span>检查</span>
            </div>
            <div class="foot-button" @click="showWebsocketDialog">
              <vab-icon icon="play-circle-line" />
              <span>运行</span>
            </div>
          </div>

          <!-- 气泡提示框 -->
          <div class="tooltip-bubble" :class="{ 'bubble-show': showTooltipBubble }">
            <div class="bubble-content">
              {{ tooltipContent }}
            </div>
            <div class="bubble-arrow"></div>
          </div>
        </div>
      </div>
    </div>

    <!-- 右键菜单 -->
    <div
      v-show="contextMenuVisible"
      class="context-menu"
      :style="{
        left: `${contextMenuPosition.x}px`,
        top: `${contextMenuPosition.y}px`,
      }"
      @contextmenu.prevent
    >
      <div v-for="option in currentMenuOptions" :key="option.value" class="menu-item" @click="handleContextMenuAction(option.value)">
        <vab-icon class="menu-icon" :icon="option.icon" />
        <span class="menu-label">{{ option.label }}</span>
        <span v-if="option.shortcut" class="menu-shortcut">{{ option.shortcut }}</span>
      </div>
    </div>

    <!-- 图纸右键菜单 -->
    <div
      v-show="drawingMenuVisible"
      class="context-menu"
      :style="{
        left: `${drawingMenuPosition.x}px`,
        top: `${drawingMenuPosition.y}px`,
      }"
      @contextmenu.prevent
    >
      <div v-for="option in drawingMenuOptions" :key="option.value" class="menu-item" @click="handleDrawingMenuAction(option.value)">
        <vab-icon class="menu-icon" :icon="option.icon" />
        <span class="menu-label">{{ option.label }}</span>
      </div>
    </div>

    <!-- 模块创建对话框 -->
    <vab-dialog v-model="moduleDialogVisible" center destroy-on-close draggable :title="moduleDialogTitle" width="620px">
      <div class="module-form">
        <el-form
          ref="moduleFormRef"
          class="module-creation-form"
          label-width="100px"
          :model="moduleFormData"
          :rules="moduleFormRules"
          size="default"
        >
          <el-form-item label="资源 ID">
            <el-input v-model="moduleFormData.resourceId" disabled />
          </el-form-item>
          <el-form-item class="model-project-id" label="模型 ID">
            <div class="id-input-group">
              <el-input v-model="moduleFormData.modelId" class="model-id" disabled />
              <span class="separator">/</span>
              <el-form-item class="nested-form-item" prop="projectId">
                <el-input v-model="moduleFormData.projectId" class="project-id" placeholder="项目ID (必填)" />
              </el-form-item>
            </div>
          </el-form-item>
          <el-form-item label="名称" prop="name" required>
            <el-input v-model="moduleFormData.name" placeholder="请输入模块名称 (必填)" />
          </el-form-item>
          <el-form-item label="权限">
            <el-radio-group v-model="moduleFormData.permission" class="permission-group">
              <el-radio label="private">私有</el-radio>
              <el-radio label="public">以为子模块公开</el-radio>
              <el-radio label="full">完全公开</el-radio>
            </el-radio-group>
          </el-form-item>
          <el-form-item label="模型类型">
            <el-select v-model="moduleFormData.type" class="type-select">
              <el-option label="元件" value="元件" />
              <el-option label="装置" value="装置" />
              <el-option label="其他" value="其他" />
            </el-select>
          </el-form-item>
          <el-form-item label="元件标签">
            <el-input v-model="moduleFormData.category" placeholder="该模型在模型库中的分组" />
          </el-form-item>
          <el-form-item label="描述">
            <el-input
              v-model="moduleFormData.description"
              placeholder="模型的简要描述，可使用 MarkDown 编写"
              resize="none"
              :rows="3"
              type="textarea"
            />
          </el-form-item>
          <el-form-item class="advanced-settings-item" label="高级设置">
            <div class="advanced-settings">
              <el-button size="small" text type="info">
                <vab-icon class="settings-icon" icon="settings-4-line" />
                隐藏高级设置
              </el-button>
            </div>
          </el-form-item>
        </el-form>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="moduleDialogVisible = false">放弃</el-button>
          <el-button type="primary" @click="createModule">创建</el-button>
        </div>
      </template>
    </vab-dialog>

    <!-- 选择组右键菜单 -->
    <div
      v-show="selectionGroupMenuVisible"
      class="context-menu"
      :style="{
        left: `${selectionGroupMenuPosition.x}px`,
        top: `${selectionGroupMenuPosition.y}px`,
      }"
      @contextmenu.prevent
    >
      <div
        v-for="option in selectionGroupMenuOptions"
        :key="option.value"
        class="menu-item"
        @click="handleSelectionGroupMenuAction(option.value)"
      >
        <vab-icon class="menu-icon" :icon="option.icon" />
        <span class="menu-label">{{ option.label }}</span>
      </div>
    </div>

    <!-- 导入JSON对话框 -->
    <el-dialog
      v-model="importDialogVisible"
      :close-on-click-modal="false"
      :show-close="true"
      title="导入JSON数据"
      width="500px"
      @closed="handleDialogClose"
    >
      <div class="import-dialog-content">
        <div class="import-tips">
          <i class="el-icon-info tip-icon"><vab-icon icon="information-line" /></i>
          <p>导入JSON数据将替换当前画布的所有内容，请确保数据格式正确。</p>
        </div>

        <div
          class="drop-zone"
          :class="{ 'is-dragging': isDraggingFile }"
          @dragleave="handleDragLeave"
          @dragover="handleDragOver"
          @drop="handleDrop"
        >
          <vab-icon class="upload-icon" icon="upload-cloud-2-line" />
          <p>将JSON文件拖放到此处，或</p>
          <el-button size="small" type="primary" @click="triggerFileSelect">选择文件</el-button>
          <input ref="fileInputRef" accept=".json,application/json" style="display: none" type="file" @change="handleFileSelect" />
        </div>

        <div v-if="selectedFileName" class="selected-file">
          <vab-icon icon="file-code-line" />
          <span>{{ selectedFileName }}</span>
          <vab-icon class="remove-file" icon="close-circle-line" @click="selectedFileName = ''" />
        </div>
      </div>

      <template #footer>
        <div class="import-dialog-footer">
          <el-button @click="importDialogVisible = false">取消</el-button>
          <el-button :disabled="!selectedFileName" type="primary" @click="importSelected">导入</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- WebSocket监控对话框 -->
    <el-dialog
      v-model="websocketDialogVisible"
      class="websocket-dialog"
      :close-on-click-modal="false"
      :show-close="true"
      title="实时系统监控"
      width="800px"
      @closed="handleWebsocketDialogClose"
    >
      <div class="websocket-container">
        <WebsocketComponent.default
          :chart-data="websocketChartData"
          :is-completed="websocketCompleted"
          :system-info-data="websocketSystemInfo"
          :threads-data="websocketThreadsData"
        />
      </div>
    </el-dialog>

    <!-- 图片上传对话框 -->
    <el-dialog v-model="imageUploadDialogVisible" :close-on-click-modal="false" :show-close="true" title="上传图片到节点" width="500px">
      <div class="image-upload-content">
        <div class="upload-tips">
          <i class="el-icon-info tip-icon"><vab-icon icon="information-line" /></i>
          <p>选择图片文件，图片将覆盖在节点上，节点的连接桩仍可正常使用。</p>
        </div>

        <div class="image-upload-zone">
          <vab-icon class="upload-icon" icon="image-add-line" />
          <p>选择图片文件</p>
          <el-button size="small" type="primary" @click="triggerImageFileSelect">选择文件</el-button>
          <input ref="imageFileInputRef" accept="image/*" style="display: none" type="file" @change="handleImageFileSelect" />
        </div>

        <div v-if="selectedImagePreview" class="image-preview">
          <div class="preview-title">图片预览：</div>
          <img alt="预览图片" class="preview-image" :src="selectedImagePreview" />
        </div>
      </div>

      <template #footer>
        <div class="image-upload-footer">
          <el-button @click="imageUploadDialogVisible = false">取消</el-button>
          <el-button :disabled="!selectedImageFile" type="primary" @click="applyImageToNode">应用到节点</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 节点气泡提示 -->
    <node-tooltip :node-id="tooltipNodeId" :node-type="tooltipNodeType" :trigger-ref="tooltipTriggerRef" :visible="tooltipVisible" />
  </div>
</template>

<style lang="scss" scoped>
.antvX6Demo-container {
  padding: 0 !important;
}
#container {
  position: relative;
  display: flex;
  align-items: center; /* Center vertically */
  justify-content: center; /* Center horizontally */
  height: calc(100vh - 225px);

  .context-left {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 10;
    display: flex;
    flex: 1;
    flex-direction: column;
    width: 240px;
    height: 100%;
    border-right: none;
    transition: opacity 0.3s ease;

    &.collapsed {
      visibility: hidden;
      pointer-events: none;
      opacity: 0;
    }

    .left-tabs {
      position: relative;
      z-index: 10;
      display: flex;
      width: 100%;
      height: 40px;
      // background-color: #f0f2f5;
      // border-bottom: 1px solid #dfe3e8;
    }

    .left-tab-item {
      display: flex;
      flex: 1;
      align-items: center;
      justify-content: center;
      height: 100%;
      font-size: 14px;
      cursor: pointer;
      transition: all 0.3s;

      &:hover {
        background-color: #e6e9ed;
      }

      &.active {
        background-color: #fff;
        border-bottom: 2px solid #409eff;
      }
    }

    .left-content {
      position: relative;
      z-index: 5;
      height: calc(100% - 80px);
      overflow-x: hidden;
      overflow-y: auto;

      border-right: 1px solid #dfe3e8;
      /* 自定义滚动条样式 */
      &::-webkit-scrollbar {
        width: 6px;
      }

      &::-webkit-scrollbar-track {
        background: #f1f1f1;
        border-radius: 3px;
      }

      &::-webkit-scrollbar-thumb {
        background: #c1c1c1;
        border-radius: 3px;

        &:hover {
          background: #a8a8a8;
        }
      }
    }

    .create-drawing {
      padding: 16px;

      h3 {
        margin-top: 0;
        margin-bottom: 16px;
        font-size: 16px;
      }

      .drawing-item {
        margin-bottom: 12px;

        .el-button {
          width: 100%;
        }
      }

      .drawing-list {
        margin-top: 24px;

        h4 {
          margin-bottom: 12px;
          font-size: 14px;
        }

        .drawing-list-item {
          display: flex;
          justify-content: space-between;
          padding: 8px;
          cursor: pointer;
          border-bottom: 1px solid #ebeef5;

          &:hover {
            background-color: #f5f7fa;
          }

          .drawing-name {
            font-size: 14px;
          }

          .drawing-date {
            font-size: 12px;
            color: #909399;
          }
        }
      }
    }

    .geo-info {
      padding: 16px;

      h3 {
        margin-top: 0;
        margin-bottom: 16px;
        font-size: 16px;
      }
    }

    #stencil {
      width: 100%;
      height: 100%;
      padding-bottom: 20px;
      margin-top: 0;
      margin-bottom: 0;
      border-right: none;
    }
  }

  .context-center {
    position: relative;
    top: -20px;
    z-index: 5;
    flex: 6;
    width: calc(100vw - 240px - 300px);
    height: calc(100vh - 260px);
    margin-right: 300px;
    margin-left: 240px;
    overflow: auto;
    transition: all 0.3s ease;

    &.left-collapsed {
      margin-left: 0;
    }

    &.right-collapsed {
      margin-right: 0;
    }

    // 添加拖拽相关样式
    &.dragging {
      cursor: grabbing !important;
      user-select: none;
      transition: none; // 拖拽时禁用过渡效果

      /* 拖拽时完全隐藏选择相关元素 */
      .x6-widget-selection,
      .x6-widget-selection-box,
      .x6-widget-selection-rubberband,
      .x6-widget-selection-inner {
        display: none !important;
        visibility: hidden !important;
        opacity: 0 !important;
      }

      /* 隐藏节点和边的选中状态 */
      .x6-node-selected,
      .x6-edge-selected {
        .x6-node-selection-box,
        .x6-edge-selection-box {
          display: none !important;
        }
      }
    }

    .center-header {
      position: sticky;
      top: 0;
      left: 0;
      z-index: 10;
      display: flex;
      align-items: center;
      width: 100%;
      height: 40px;
      padding: 0 10px;
      background-color: #f0f2f5;
      border-bottom: 1px solid #dfe3e8;

      .toggle-sidebar {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 24px;
        height: 24px;
        cursor: pointer;
        border-radius: 4px;
        transition: background-color 0.3s;

        &:hover {
          background-color: #e6e9ed;
        }

        &.left {
          margin-right: 10px;
        }

        &.right {
          margin-left: 10px;
        }
      }

      .header-tabs {
        display: flex;
        flex: 1;
        height: 100%;
        overflow-x: auto;

        .header-tab {
          display: flex;
          align-items: center;
          padding: 0 15px;
          margin-right: 2px;
          font-size: 14px;
          cursor: pointer;
          background-color: #e6e9ed;
          border-radius: 4px 4px 0 0;
          transition: background-color 0.2s;

          &:hover {
            background-color: #eaedf0;
          }

          &.active {
            background-color: #fff;
            border-bottom: 2px solid #409eff;
          }

          &.add-tab {
            justify-content: center;
            width: 36px;
            padding: 0;
            color: #606266;

            &:hover {
              color: #409eff;
            }
          }

          .close-icon {
            margin-left: 8px;
            font-size: 12px;
            cursor: pointer;

            &:hover {
              color: #f56c6c;
            }
          }
        }
      }
    }
    .center-content {
      position: relative;
      width: 100%;
      height: calc(100vh - 300px);
      overflow: hidden;

      #graph-container {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        margin: 0;
        overflow: hidden;
        background-color: #fff;
        border-radius: 8px;
        box-shadow:
          0 6px 16px rgba(0, 0, 0, 0.08),
          0 3px 6px -4px rgba(0, 0, 0, 0.12);

        .zoom-indicator {
          position: absolute;
          top: 10px;
          right: 10px;
          z-index: 1000;
          padding: 6px 12px;
          font-size: 12px;
          font-weight: 500;
          color: white;
          pointer-events: none;
          background-color: rgba(0, 0, 0, 0.75);
          border: 1px solid rgba(255, 255, 255, 0.1);
          border-radius: 6px;
          opacity: 1;
          transition: all 0.3s ease;

          &.zoom-active {
            background-color: rgba(24, 144, 255, 0.85);
            box-shadow: 0 2px 8px rgba(24, 144, 255, 0.3);
            transform: scale(1.05);
          }
        }
      }
    }
  }

  .context-right {
    position: absolute;
    top: 0;
    right: 0;
    z-index: 10;
    width: 300px;
    height: 100%;
    overflow: hidden;
    background-color: #fff;
    border-left: 1px solid #dfe3e8;
    transition: opacity 0.3s ease;

    &.collapsed {
      visibility: hidden;
      pointer-events: none;
      opacity: 0;
    }

    .antvX6Demo-container-right {
      position: absolute;
      top: 0;
      right: 0;
      display: flex;
      flex-direction: column;
      width: 300px;
      height: 100%;
      overflow: hidden;
      background-color: #fff;
      border-left: 1px solid #dfe3e8;
    }
  }
  .context-foot {
    position: absolute;
    bottom: 0;
    left: 0;
    z-index: 100;
    width: 100%;
    height: 40px;
    background-color: #f0f2f5;
    border-top: 1px solid #e0e0e0;

    .foot-content {
      position: relative;
      display: flex;
      align-items: center;
      justify-content: space-between;
      width: 100%;
      height: 100%;
      padding: 0 15px;

      .foot-left {
        display: flex;
        align-items: center;

        .foot-button {
          display: flex;
          align-items: center;
          padding: 0 8px;
          margin-right: 15px;
          font-size: 14px;
          color: #606266;
          cursor: pointer;
          transition: all 0.2s;

          i {
            margin-right: 5px;
            font-size: 16px;
          }

          &:hover {
            color: #409eff;
          }
        }
      }

      .foot-right {
        font-size: 14px;
        color: #909399;
      }

      // 气泡提示框样式
      .tooltip-bubble {
        position: absolute;
        bottom: 50px;
        left: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
        pointer-events: none;
        opacity: 0;
        transform: translateY(20px);
        transition: all 0.3s ease;

        &.bubble-show {
          opacity: 1;
          transform: translateY(0);
        }

        .bubble-content {
          padding: 10px 15px;
          font-size: 14px;
          color: #666;
          white-space: nowrap;
          background-color: #fff;
          border-radius: 4px;
          box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
        }

        .bubble-arrow {
          width: 0;
          height: 0;
          margin-top: -1px;
          border-top: 8px solid #fff;
          border-right: 8px solid transparent;
          border-left: 8px solid transparent;
        }
      }
    }
  }
}

.properties-header {
  padding: 0 10px;
}
.properties-content {
  flex: 1;
  padding: 10px 20px;
  padding-bottom: 50px;
  overflow-y: auto;
}
.property-item {
  display: flex;
  align-items: center;
  margin-bottom: 15px;
}
.property-label {
  flex: 0 0 120px;
  font-size: 14px;
}
.property-value {
  flex: 1;
}

/* 右键菜单样式 */
.context-menu {
  position: fixed;
  z-index: 9999;
  min-width: 200px;
  padding: 5px 0;
  background-color: #fff;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.menu-item {
  display: flex;
  align-items: center;
  padding: 8px 16px;
  font-size: 14px;
  cursor: pointer;

  &:hover {
    background-color: #f5f7fa;
  }

  .menu-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    margin-right: 8px;
    font-size: 16px;
    color: #606266;
  }

  .menu-label {
    flex: 1;
  }

  .menu-shortcut {
    margin-left: 8px;
    font-size: 12px;
    color: #909399;
  }
}
/* 空状态样式 */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 30px 20px;
  color: #909399;
  text-align: center;

  p {
    margin: 10px 0;
    font-size: 14px;
  }
}

:deep() {
  .x6-widget-stencil {
    width: 240px;
    padding-bottom: 40px !important;
    margin-top: 0 !important;
    background-color: #fff !important;
    border: none !important;
  }

  .x6-widget-stencil-title,
  .x6-widget-stencil-group-title {
    width: 240px;
    margin-top: 0 !important;
    background-color: #fff !important;
    border: none !important;
  }
  .x6-widget-transform,
  .x6-widget-selection-box,
  .x6-widget-selection-inner {
    border: 1px dashed #239edd;
    vector-effect: non-scaling-stroke; /* Ensures borders maintain width during zoom */
  }

  /* 让边跟随缩放 */
  .x6-edge path {
    /* 移除 vector-effect: non-scaling-stroke; 让边跟随画布缩放 */
  }

  /* Keep consistent border width for nodes during zoom */
  .x6-node rect,
  .x6-node circle,
  .x6-node path,
  .x6-node polygon {
    vector-effect: non-scaling-stroke;
  }

  .el-tabs__item {
    font-size: 14px;
  }
  .el-select {
    width: 100%;
  }
}

// .center-content {
//   position: relative;
//   transition: transform 0.05s ease;

//   &.dragging {
//     transition: none; // 拖拽时禁用过渡效果
//   }
// }

.module-form {
  padding: 10px 15px;
}

.module-creation-form {
  .el-form-item {
    margin-bottom: 18px;
  }

  .id-input-group {
    display: flex;
    align-items: center;
    width: 100%;

    .model-id {
      flex: 1;
      max-width: 180px;
    }

    .separator {
      margin: 0 8px;
      color: var(--el-text-color-secondary);
    }

    .project-id {
      flex: 1;
    }
  }

  .permission-group {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
  }

  .type-select {
    width: 100%;
  }

  .advanced-settings-item {
    margin-bottom: 0;
  }

  .advanced-settings {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 5px;

    .settings-icon {
      margin-right: 5px;
      font-size: 16px;
    }
  }
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  padding: 10px 0;
}

.module-canvas-container {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.module-canvas {
  width: 100%;
  height: 100%;
  background-color: #f8f9fa;
}

.module-canvas-dialog {
  .el-dialog__body {
    padding: 0;
  }

  .module-canvas-container {
    height: calc(100vh - 200px);
    padding: 20px;
  }

  .module-info-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 20px;

    .module-info {
      display: flex;
      align-items: center;

      .module-title {
        margin-right: 10px;
        font-size: 16px;
        font-weight: bold;
      }

      .module-id {
        font-size: 14px;
        color: #909399;
      }
    }

    .module-actions {
      display: flex;
      align-items: center;

      .el-button {
        margin-left: 10px;
      }
    }
  }
}

.groups-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;

  .groups-title {
    font-size: 16px;
    font-weight: bold;
  }

  .groups-toggle {
    font-size: 14px;
    cursor: pointer;
  }
}

.groups-list {
  margin-bottom: 10px;

  .group-list-item {
    display: flex;
    align-items: center;
    padding: 5px;
    margin-bottom: 5px;
    cursor: pointer;
    background-color: #f8f9fa;
    border-radius: 4px;

    &:hover {
      background-color: #e6e9ed;
    }

    &.active {
      background-color: #eaf4fe;
      border: 1px solid #5f95ff;
    }

    .group-color {
      width: 10px;
      height: 10px;
      margin-right: 5px;
      border-radius: 50%;
    }

    .group-name {
      flex: 1;
    }
  }
}

.group-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 10px;

  .el-button {
    margin-left: 10px;
  }
}

.groups-back {
  font-size: 14px;
  cursor: pointer;
}

.property-section {
  padding-top: 8px;
  margin-bottom: 20px;
  border-top: 1px solid #e6e6e6;

  .section-title {
    padding-bottom: 6px;
    margin-bottom: 12px;
    font-size: 14px;
    font-weight: bold;
    color: #606266;
    border-bottom: 1px solid #ebeef5;
  }

  .property-item {
    &.full-width {
      box-sizing: border-box;
      flex-basis: 100%;
      width: 100%;
    }

    &.half-width {
      box-sizing: border-box;
      display: inline-flex;
      flex-basis: 50%;
      width: 50%;
      padding: 0 4px;
      padding-right: 8px;

      .el-button {
        justify-content: center;
        width: 100%;
      }
    }

    &.third-width {
      box-sizing: border-box;
      display: inline-flex;
      flex-basis: 33.33%;
      width: 33.33%;
      padding-right: 8px;
    }
  }
}

.required {
  color: #f56c6c;
}

// 添加宽度变体样式
.property-item.full-width {
  box-sizing: border-box;
  flex-basis: 100%;
  width: 100%;
}

.property-item.half-width {
  box-sizing: border-box;
  display: inline-flex;
  flex-basis: 50%;
  width: 50%;
  padding-right: 8px;
}

.property-item.third-width {
  box-sizing: border-box;
  display: inline-flex;
  flex-basis: 33.33%;
  width: 33.33%;
  padding-right: 8px;
}

.section-title {
  padding-bottom: 6px;
  margin-bottom: 12px;
  font-size: 16px;
  font-weight: bold;
  border-bottom: 1px solid #ebeef5;
}

.header-actions {
  display: flex;
  align-items: center;
  margin-right: 10px;

  .import-btn {
    padding: 6px;
    font-size: 16px;
    color: #409eff;
    background-color: transparent;
    border: none;

    &:hover {
      color: #66b1ff;
      background-color: rgba(64, 158, 255, 0.1);
    }
  }
}

.import-dialog-content {
  display: flex;
  flex-direction: column;
  align-items: stretch;

  .import-tips {
    display: flex;
    align-items: flex-start;
    padding: 10px;
    margin-bottom: 20px;
    background-color: #f0f9ff;
    border-radius: 4px;

    .tip-icon {
      margin-right: 10px;
      font-size: 18px;
      color: #409eff;
    }

    p {
      margin: 0;
      font-size: 14px;
      line-height: 1.5;
      color: #606266;
    }
  }

  .drop-zone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 180px;
    padding: 20px;
    margin-bottom: 20px;
    cursor: pointer;
    background-color: #f5f7fa;
    border: 2px dashed #c0c4cc;
    border-radius: 6px;
    transition: all 0.3s;

    &:hover {
      background-color: #f0f9ff;
      border-color: #409eff;
    }

    &.is-dragging {
      background-color: #ecf5ff;
      border-color: #409eff;
    }

    .upload-icon {
      margin-bottom: 10px;
      font-size: 48px;
      color: #909399;
    }

    p {
      margin: 0 0 15px;
      color: #606266;
    }
  }

  .selected-file {
    display: flex;
    align-items: center;
    padding: 10px 15px;
    background-color: #f5f7fa;
    border-radius: 4px;

    i {
      margin-right: 8px;
      color: #409eff;
    }

    span {
      flex: 1;
      overflow: hidden;
      text-overflow: ellipsis;
      color: #606266;
      white-space: nowrap;
    }

    .remove-file {
      color: #909399;
      cursor: pointer;

      &:hover {
        color: #f56c6c;
      }
    }
  }
}

.import-dialog-footer {
  display: flex;
  justify-content: flex-end;
}

.foot-left {
  display: flex;
  gap: 16px;
}

.foot-button {
  display: flex;
  align-items: center;
  padding: 8px 16px;
  cursor: pointer;
  background-color: #f0f2f5;
  border-radius: 4px;
  transition: background-color 0.3s;

  &:hover {
    background-color: #e0e4ea;
  }

  .vab-icon {
    margin-right: 6px;
    font-size: 16px;
  }
}

.websocket-dialog {
  :deep(.el-dialog__body) {
    max-height: 70vh;
    padding: 0;
    overflow-y: auto;
  }

  .websocket-container {
    height: 70vh;
    overflow-y: auto;
  }
}

/* 拖拽提示样式 */
.property-hint {
  padding: 8px 12px;
  margin-top: 8px;
  margin-bottom: 12px;
  background: linear-gradient(90deg, #f0f9ff 0%, #e0f2fe 100%);
  border-left: 3px solid #0ea5e9;
  border-radius: 6px;

  .el-text {
    font-size: 12px;
    line-height: 1.5;
  }
}

/* 拖拽状态样式优化 */
.dragging {
  cursor: grabbing !important;
  user-select: none !important;

  * {
    pointer-events: none !important;
  }

  /* 拖拽时隐藏所有选择框和选择相关元素 */
  .x6-widget-selection,
  .x6-widget-selection-box,
  .x6-widget-selection-rubberband,
  .x6-widget-selection-inner,
  .x6-node-selected .x6-node-selection-box,
  .x6-edge-selected .x6-edge-selection-box {
    display: none !important;
    visibility: hidden !important;
    opacity: 0 !important;
  }
}

/* 画布容器拖拽样式 */
#graph-container {
  transition: cursor 0.1s ease;

  &.drag-enabled {
    cursor: grab;

    &:active {
      cursor: grabbing;
    }
  }
}

/* 链接桩优化样式 */
.x6-port-body {
  pointer-events: all !important;
  cursor: crosshair !important;
  transition: all 0.2s ease !important;

  &:hover {
    filter: drop-shadow(0 2px 4px rgba(24, 144, 255, 0.3)) !important;
    transform: scale(1.2) !important;
  }
}

/* 链接桩可见时的样式 */
.x6-port[style*='visible'] .x6-port-body {
  animation: portPulse 2s infinite;
}

@keyframes portPulse {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.7;
    transform: scale(1.1);
  }
}

/* 增强链接桩的点击区域 */
.x6-port {
  cursor: crosshair !important;
}

/* 连接线吸附时的链接桩样式 */
.x6-port.available .x6-port-body {
  filter: drop-shadow(0 2px 6px rgba(82, 196, 26, 0.4)) !important;
  fill: #52c41a !important;
  stroke: #389e0d !important;
  transform: scale(1.3) !important;
}

/* 连接线悬停时的链接桩样式 */
.x6-port.adsorbed .x6-port-body {
  filter: drop-shadow(0 2px 8px rgba(255, 77, 79, 0.5)) !important;
  fill: #ff7875 !important;
  stroke: #ff4d4f !important;
  transform: scale(1.4) !important;
}

/* 图片上传对话框样式 */
.image-upload-content {
  .upload-tips {
    display: flex;
    align-items: flex-start;
    padding: 12px;
    margin-bottom: 20px;
    background-color: #e1f3d8;
    border-radius: 6px;

    .tip-icon {
      margin-top: 2px;
      margin-right: 8px;
      font-size: 16px;
      color: #67c23a;
    }

    p {
      margin: 0;
      font-size: 14px;
      line-height: 1.5;
      color: #606266;
    }
  }

  .image-upload-zone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 40px 20px;
    text-align: center;
    background-color: #fafafa;
    border: 2px dashed #c0c4cc;
    border-radius: 6px;
    transition: all 0.3s;

    &:hover {
      background-color: #f0f9ff;
      border-color: #409eff;
    }

    .upload-icon {
      margin-bottom: 10px;
      font-size: 48px;
      color: #909399;
    }

    p {
      margin: 0 0 15px;
      color: #606266;
    }
  }

  .image-preview {
    margin-top: 20px;

    .preview-title {
      margin-bottom: 10px;
      font-size: 14px;
      font-weight: 500;
      color: #303133;
    }

    .preview-image {
      display: block;
      max-width: 100%;
      max-height: 200px;
      margin: 0 auto;
      border-radius: 6px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    }
  }
}

.image-upload-footer {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

// 边参数面板样式
.edge-parameters-panel {
  padding: 16px;

  .parameter-header {
    margin-bottom: 20px;
    padding-bottom: 12px;
    border-bottom: 1px solid #ebeef5;

    .parameter-title {
      display: flex;
      align-items: center;
      margin-bottom: 4px;
      font-size: 16px;
      font-weight: 600;
      color: #303133;

      .el-icon {
        margin-right: 8px;
        color: #409eff;
      }
    }

    .parameter-subtitle {
      font-size: 12px;
      color: #90939d;
    }
  }

  .no-parameters-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 40px 20px;
    text-align: center;
    background-color: #fafbfc;
    border: 1px dashed #d0d7de;
    border-radius: 8px;

    .placeholder-icon {
      margin-bottom: 12px;
      font-size: 36px;
      color: #8c939d;
    }

    .placeholder-text {
      margin-bottom: 8px;
      font-size: 14px;
      font-weight: 500;
      color: #656d76;
    }

    .placeholder-hint {
      font-size: 12px;
      color: #8c939d;
      line-height: 1.4;
    }
  }
}
</style>
